blob: 5012e8b5c4aaabb80cb1df21f8034d255a39d765 [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002/**************************************************************************
3 * nano.c *
4 * *
Jordi Mallach8ae57892002-01-04 17:57:40 +00005 * Copyright (C) 1999-2002 Chris Allegretta *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00006 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
Chris Allegretta3a24f3f2001-10-24 11:33:54 +00008 * the Free Software Foundation; either version 2, or (at your option) *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00009 * any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 * *
20 **************************************************************************/
21
Chris Allegretta6efda542001-04-28 18:03:52 +000022#include "config.h"
23
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000024#include <stdio.h>
25#include <stdlib.h>
26#include <stdarg.h>
27#include <signal.h>
Chris Allegretta08020882001-01-29 23:37:54 +000028#include <setjmp.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000029#include <unistd.h>
30#include <string.h>
31#include <fcntl.h>
32#include <sys/stat.h>
33#include <sys/ioctl.h>
34#include <sys/param.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000035#include <sys/types.h>
36#include <sys/wait.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000037#include <errno.h>
38#include <ctype.h>
39#include <locale.h>
40#include <limits.h>
Adam Rogoyski77f36de2000-06-07 03:56:54 +000041#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000042#include "proto.h"
43#include "nano.h"
44
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000045#ifdef HAVE_TERMIOS_H
46#include <termios.h>
47#endif
48
49#ifdef HAVE_TERMIO_H
50#include <termio.h>
51#endif
52
53#ifdef HAVE_GETOPT_H
54#include <getopt.h>
55#endif
56
Chris Allegretta6fe61492001-05-21 12:56:25 +000057#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +000058static int fill = 0; /* Fill - where to wrap lines, basically */
Chris Allegretta6fe61492001-05-21 12:56:25 +000059#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000060
Chris Allegretta6df90f52002-07-19 01:08:59 +000061static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000062static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000063
Chris Allegretta08020882001-01-29 23:37:54 +000064static sigjmp_buf jmpbuf; /* Used to return to mainloop after SIGWINCH */
65
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000066/* What we do when we're all set to exit */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +000067RETSIGTYPE finish(int sigage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000068{
Chris Allegrettac08f50d2001-01-06 18:12:43 +000069 keypad(edit, TRUE);
70 keypad(bottomwin, TRUE);
71
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000072 if (!ISSET(NO_HELP)) {
73 mvwaddstr(bottomwin, 1, 0, hblank);
74 mvwaddstr(bottomwin, 2, 0, hblank);
Chris Allegretta4da1fc62000-06-21 03:00:43 +000075 } else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000076 mvwaddstr(bottomwin, 0, 0, hblank);
Chris Allegretta6b58acd2001-04-12 03:01:53 +000077
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000078 wrefresh(bottomwin);
79 endwin();
80
81 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000082 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000083
Chris Allegretta6232d662002-05-12 19:52:15 +000084#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000085 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +000086#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000087
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000088 exit(sigage);
89}
90
91/* Die (gracefully?) */
Chris Allegretta6df90f52002-07-19 01:08:59 +000092void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000093{
94 va_list ap;
95
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000096 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000097 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000098
99 clear();
100 refresh();
101 resetty();
102 endwin();
103
Chris Allegretta6df90f52002-07-19 01:08:59 +0000104 va_start(ap, msg);
105 vfprintf(stderr, msg, ap);
106 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000107
Chris Allegretta32da4562002-01-02 15:12:21 +0000108 /* save the currently loaded file if it's been modified */
109 if (ISSET(MODIFIED))
110 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000111
Chris Allegretta355fbe52001-07-14 19:32:47 +0000112#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000113 /* then save all of the other modified loaded files, if any */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000114 if (open_files != NULL) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000115 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000116
117 tmp = open_files;
118
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000119 while (open_files->prev != NULL)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000120 open_files = open_files->prev;
121
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000122 while (open_files->next != NULL) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000123
124 /* if we already saved the file above (i. e. if it was the
125 currently loaded file), don't save it again */
126 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000127 /* make sure open_files->fileage and fileage, and
128 open_files->filebot and filebot, are in sync; they
129 might not be if lines have been cut from the top or
130 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000131 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000132 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000133 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000134 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000135 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000136 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000137 open_files = open_files->next;
138 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000139 }
140#endif
141
Chris Allegretta6df90f52002-07-19 01:08:59 +0000142 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000143}
144
Chris Allegretta6df90f52002-07-19 01:08:59 +0000145void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000146{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000147 char *ret;
Chris Allegretta48b06702002-02-22 04:30:50 +0000148 int i = -1;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000149
Chris Allegretta6df90f52002-07-19 01:08:59 +0000150 /* If we can't save, we have REAL bad problems, but we might as well
151 TRY. */
152 if (die_filename[0] == '\0')
153 ret = get_next_filename("nano.save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000154 else {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000155 char *buf = charalloc(strlen(die_filename) + 6);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000156
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000157 strcpy(buf, die_filename);
158 strcat(buf, ".save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000159 ret = get_next_filename(buf);
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000160 free(buf);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000161 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000162 if (ret[0] != '\0')
163 i = write_file(ret, 1, 0, 0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000164
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000165 if (i != -1)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000166 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000167 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000168 fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000169
170 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000171}
172
Chris Allegrettae61e8302001-01-14 05:18:27 +0000173/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000174 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000175void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000176{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000177 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000178}
179
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000180void print_view_warning(void)
181{
182 statusbar(_("Key illegal in VIEW mode"));
183}
184
Chris Allegretta56214c62001-09-27 02:46:53 +0000185/* Initialize global variables - no better way for now. If
Chris Allegretta6df90f52002-07-19 01:08:59 +0000186 * save_cutbuffer is nonzero, don't set cutbuffer to NULL. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000187void global_init(int save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000188{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000189 current_x = 0;
190 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000191
192 if ((editwinrows = LINES - 5 + no_help()) < MIN_EDITOR_ROWS)
193 die_too_small();
194
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000195 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000196 if (!save_cutbuffer)
197 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000198 current = NULL;
199 edittop = NULL;
200 editbot = NULL;
201 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000202 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000203 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000204
Chris Allegretta6fe61492001-05-21 12:56:25 +0000205#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000206 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000207 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000208 fill += COLS;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000209 if (fill < MIN_FILL_LENGTH)
210 die_too_small();
Chris Allegretta6fe61492001-05-21 12:56:25 +0000211#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000212
Chris Allegretta88b09152001-05-17 11:35:43 +0000213 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000214 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000215 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000216}
217
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000218void window_init(void)
219{
220 if ((editwinrows = LINES - 5 + no_help()) < MIN_EDITOR_ROWS)
221 die_too_small();
222
223 /* Set up the main text window */
224 edit = newwin(editwinrows, COLS, 2, 0);
225
226 /* And the other windows */
227 topwin = newwin(2, COLS, 0, 0);
228 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
229
230#ifdef PDCURSES
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000231 /* Oops, I guess we need this again. Moved here so the keypad still
232 works after a Meta-X, for example */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000233 keypad(edit, TRUE);
234 keypad(bottomwin, TRUE);
235#endif
236}
237
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000238#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000239void mouse_init(void)
240{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000241 if (ISSET(USE_MOUSE)) {
242 keypad_on(edit, 1);
243 keypad_on(bottomwin, 1);
244
245 mousemask(BUTTON1_RELEASED, NULL);
246 mouseinterval(50);
247 } else
248 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000249}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000250#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000251
252#ifndef DISABLE_HELP
253/* This function allocates help_text, and stores the help string in it.
254 * help_text should be NULL initially. */
255void help_init(void)
256{
257 size_t allocsize = 1; /* space needed for help_text */
258 char *ptr = NULL;
259#ifndef NANO_SMALL
260 const toggle *t;
261#endif
262 const shortcut *s;
263
264 /* First set up the initial help text for the current function */
265 if (currshortcut == whereis_list || currshortcut == replace_list
266 || currshortcut == replace_list_2)
267 ptr = _("Search Command Help Text\n\n "
268 "Enter the words or characters you would like to search "
269 "for, then hit enter. If there is a match for the text you "
270 "entered, the screen will be updated to the location of the "
271 "nearest match for the search string.\n\n "
272 "If using Pico Mode via the -p or --pico flags, the "
273 "Meta-P toggle, or a nanorc file, the previous search "
274 "string will be shown in brackets after the Search: prompt. "
275 "Hitting Enter without entering any text will perform the "
276 "previous search. Otherwise, the previous string will be "
277 "placed before the cursor, and can be edited or deleted "
278 "before hitting enter.\n\n The following function keys are "
279 "available in Search mode:\n\n");
280 else if (currshortcut == goto_list)
281 ptr = _("Go To Line Help Text\n\n "
282 "Enter the line number that you wish to go to and hit "
283 "Enter. If there are fewer lines of text than the "
284 "number you entered, you will be brought to the last line "
285 "of the file.\n\n The following function keys are "
286 "available in Go To Line mode:\n\n");
287 else if (currshortcut == insertfile_list)
288 ptr = _("Insert File Help Text\n\n "
289 "Type in the name of a file to be inserted into the current "
290 "file buffer at the current cursor location.\n\n "
291 "If you have compiled nano with multiple file buffer "
292 "support, and enable multiple buffers with the -F "
293 "or --multibuffer command line flags, the Meta-F toggle, or "
294 "a nanorc file, inserting a file will cause it to be "
295 "loaded into a separate buffer (use Meta-< and > to switch "
296 "between file buffers).\n\n If you need another blank "
297 "buffer, do not enter any filename, or type in a "
298 "nonexistent filename at the prompt and press "
299 "Enter.\n\n The following function keys are "
300 "available in Insert File mode:\n\n");
301 else if (currshortcut == writefile_list)
302 ptr = _("Write File Help Text\n\n "
303 "Type the name that you wish to save the current file "
304 "as and hit Enter to save the file.\n\n If you have "
305 "selected text with Ctrl-^, you will be prompted to "
306 "save only the selected portion to a separate file. To "
307 "reduce the chance of overwriting the current file with "
308 "just a portion of it, the current filename is not the "
309 "default in this mode.\n\n The following function keys "
310 "are available in Write File mode:\n\n");
311#ifndef DISABLE_BROWSER
312 else if (currshortcut == browser_list)
313 ptr = _("File Browser Help Text\n\n "
314 "The file browser is used to visually browse the "
315 "directory structure to select a file for reading "
316 "or writing. You may use the arrow keys or Page Up/"
317 "Down to browse through the files, and S or Enter to "
318 "choose the selected file or enter the selected "
319 "directory. To move up one level, select the directory "
320 "called \"..\" at the top of the file list.\n\n The "
321 "following function keys are available in the file "
322 "browser:\n\n");
323 else if (currshortcut == gotodir_list)
324 ptr = _("Browser Go To Directory Help Text\n\n "
325 "Enter the name of the directory you would like to "
326 "browse to.\n\n If tab completion has not been disabled, "
327 "you can use the TAB key to (attempt to) automatically "
328 "complete the directory name.\n\n The following function "
329 "keys are available in Browser Go To Directory mode:\n\n");
330#endif
331 else if (currshortcut == spell_list)
332 ptr = _("Spell Check Help Text\n\n "
333 "The spell checker checks the spelling of all text "
334 "in the current file. When an unknown word is "
335 "encountered, it is highlighted and a replacement can "
336 "be edited. It will then prompt to replace every "
337 "instance of the given misspelled word in the "
338 "current file.\n\n The following other functions are "
339 "available in Spell Check mode:\n\n");
340#ifndef NANO_SMALL
341 else if (currshortcut == extcmd_list)
342 ptr = _("External Command Help Text\n\n "
343 "This menu allows you to insert the output of a command "
344 "run by the shell into the current buffer (or a new "
345 "buffer in multibuffer mode).\n\n The following keys are "
346 "available in this mode:\n\n");
347#endif
348 else /* Default to the main help list */
349 ptr = _(" nano help text\n\n "
350 "The nano editor is designed to emulate the functionality and "
351 "ease-of-use of the UW Pico text editor. There are four main "
352 "sections of the editor: The top line shows the program "
353 "version, the current filename being edited, and whether "
354 "or not the file has been modified. Next is the main editor "
355 "window showing the file being edited. The status line is "
356 "the third line from the bottom and shows important messages. "
357 "The bottom two lines show the most commonly used shortcuts "
358 "in the editor.\n\n "
359 "The notation for shortcuts is as follows: Control-key "
360 "sequences are notated with a caret (^) symbol and are entered "
361 "with the Control (Ctrl) key. Escape-key sequences are notated "
362 "with the Meta (M) symbol and can be entered using either the "
363 "Esc, Alt or Meta key depending on your keyboard setup. The "
364 "following keystrokes are available in the main editor window. "
365 "Alternative keys are shown in parentheses:\n\n");
366
367 allocsize += strlen(ptr);
368
369 /* The space needed for the shortcut lists, at most COLS characters,
370 * plus '\n'. */
371 allocsize += (COLS + 1) * length_of_list(currshortcut);
372
373#ifndef NANO_SMALL
374 /* If we're on the main list, we also count the toggle help text.
375 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
376 * COLS - 24 characters, plus '\n'.*/
377 if (currshortcut == main_list)
378 for (t = toggles; t != NULL; t = t->next)
379 allocsize += COLS - 17;
380#endif /* !NANO_SMALL */
381
382 /* help_text has been freed and set to NULL unless the user resized
383 * while in the help screen. */
384 free(help_text);
385
386 /* Allocate space for the help text */
387 help_text = charalloc(allocsize);
388
389 /* Now add the text we want */
390 strcpy(help_text, ptr);
391 ptr = help_text + strlen(help_text);
392
393 /* Now add our shortcut info */
394 for (s = currshortcut; s != NULL; s = s->next) {
395 /* true if the character in s->altval is shown in first column */
396 int meta_shortcut = 0;
397
398 if (s->val > 0 && s->val < 32)
399 ptr += sprintf(ptr, "^%c", s->val + 64);
400#ifndef NANO_SMALL
401 else if (s->val == NANO_CONTROL_SPACE)
402 ptr += sprintf(ptr, "^%.6s", _("Space"));
403 else if (s->altval == NANO_ALT_SPACE) {
404 meta_shortcut = 1;
405 ptr += sprintf(ptr, "M-%.5s", _("Space"));
406 }
407#endif
408 else if (s->altval > 0) {
409 meta_shortcut = 1;
410 ptr += sprintf(ptr, "M-%c", s->altval -
411 (('A' <= s->altval && s->altval <= 'Z') ||
412 'a' <= s->altval ? 32 : 0));
413 }
414 /* Hack */
415 else if (s->val >= 'a') {
416 meta_shortcut = 1;
417 ptr += sprintf(ptr, "M-%c", s->val - 32);
418 }
419
420 *(ptr++) = '\t';
421
422 if (s->misc1 > KEY_F0 && s->misc1 <= KEY_F(64))
423 ptr += sprintf(ptr, "(F%d)", s->misc1 - KEY_F0);
424
425 *(ptr++) = '\t';
426
427 if (!meta_shortcut && s->altval > 0)
428 ptr += sprintf(ptr, "(M-%c)", s->altval -
429 (('A' <= s->altval && s->altval <= 'Z') || 'a' <= s->altval
430 ? 32 : 0));
431
432 *(ptr++) = '\t';
433
434 assert(s->help != NULL);
435 ptr += sprintf(ptr, "%.*s\n", COLS - 24, s->help);
436 }
437
438#ifndef NANO_SMALL
439 /* And the toggles... */
440 if (currshortcut == main_list)
441 for (t = toggles; t != NULL; t = t->next) {
442 ptr += sprintf(ptr, "M-%c\t\t\t", t->val - 32);
443 assert(t->desc != NULL);
444 ptr += sprintf(ptr, _("%.*s enable/disable\n"), COLS - 24, t->desc);
445 }
446#endif /* !NANO_SMALL */
447
448 /* If all went well, we didn't overwrite the allocated space for
449 help_text. */
450 assert(strlen(help_text) < allocsize);
451}
452#endif
453
454/* Create a new filestruct node. Note that we specifically do not set
455 * prevnode->next equal to the new line. */
456filestruct *make_new_node(filestruct *prevnode)
457{
458 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
459
460 newnode->data = NULL;
461 newnode->prev = prevnode;
462 newnode->next = NULL;
463 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
464
465 return newnode;
466}
467
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000468/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000469filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000470{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000471 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000472
Chris Allegretta6df90f52002-07-19 01:08:59 +0000473 assert(src != NULL);
474
Chris Allegretta88b09152001-05-17 11:35:43 +0000475 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000476 dst->next = src->next;
477 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000478 strcpy(dst->data, src->data);
479 dst->lineno = src->lineno;
480
481 return dst;
482}
483
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000484/* Splice a node into an existing filestruct. */
485void splice_node(filestruct *begin, filestruct *newnode, filestruct *end)
486{
487 if (newnode != NULL) {
488 newnode->next = end;
489 newnode->prev = begin;
490 }
491 if (begin != NULL)
492 begin->next = newnode;
493 if (end != NULL)
494 end->prev = newnode;
495}
496
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000497/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000498void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000499{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000500 assert(fileptr != NULL);
501
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000502 if (fileptr->prev != NULL)
503 fileptr->prev->next = fileptr->next;
504
505 if (fileptr->next != NULL)
506 fileptr->next->prev = fileptr->prev;
507}
508
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000509/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000510void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000511{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000512 if (fileptr != NULL) {
513 if (fileptr->data != NULL)
514 free(fileptr->data);
515 free(fileptr);
516 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000517}
518
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000519/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000520filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000521{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000522 filestruct *head; /* copy of src, top of the copied list */
523 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000524
Chris Allegretta6df90f52002-07-19 01:08:59 +0000525 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000526
Chris Allegretta6df90f52002-07-19 01:08:59 +0000527 prev = copy_node(src);
528 prev->prev = NULL;
529 head = prev;
530 src = src->next;
531 while (src != NULL) {
532 prev->next = copy_node(src);
533 prev->next->prev = prev;
534 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000535
Chris Allegretta6df90f52002-07-19 01:08:59 +0000536 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000537 }
538
Chris Allegretta6df90f52002-07-19 01:08:59 +0000539 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000540 return head;
541}
542
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000543/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000544void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000545{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000546 if (src != NULL) {
547 while (src->next != NULL) {
548 src = src->next;
549 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000550#ifdef DEBUG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000551 fprintf(stderr, _("delete_node(): free'd a node, YAY!\n"));
552#endif
553 }
554 delete_node(src);
555#ifdef DEBUG
556 fprintf(stderr, _("delete_node(): free'd last node.\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000557#endif
558 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000559}
560
Chris Allegretta6df90f52002-07-19 01:08:59 +0000561void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000562{
563 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000564 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000565
Chris Allegretta6df90f52002-07-19 01:08:59 +0000566 assert(fileage == NULL || fileage != fileage->next);
567 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000568 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000569}
570
Chris Allegretta6df90f52002-07-19 01:08:59 +0000571void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000572{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000573 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000574 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000575 else {
576 int lineno = fileptr->prev->lineno;
577
578 assert(fileptr != fileptr->next);
579 for (; fileptr != NULL; fileptr = fileptr->next)
580 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000581 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000582}
583
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000584/* Print one usage string to the screen, removes lots of duplicate
Chris Allegretta6df90f52002-07-19 01:08:59 +0000585 * strings to translate and takes out the parts that shouldn't be
586 * translatable (the flag names). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000587void print1opt(const char *shortflag, const char *longflag,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000588 const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000589{
590 printf(" %s\t", shortflag);
591 if (strlen(shortflag) < 8)
592 printf("\t");
593
594#ifdef HAVE_GETOPT_LONG
595 printf("%s\t", longflag);
596 if (strlen(longflag) < 8)
597 printf("\t\t");
598 else if (strlen(longflag) < 16)
599 printf("\t");
600#endif
601
602 printf("%s\n", desc);
603}
604
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000605void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000606{
607#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000608 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
609 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000610#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000611 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
612 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000613#endif /* HAVE_GETOPT_LONG */
614
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000615 print1opt("-h, -?", "--help", _("Show this message"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000616 print1opt(_("+LINE"), "", _("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000617#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000618 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000619 print1opt("-D", "--dos", _("Write file in DOS format"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000620#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000621#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000622 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000623#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000624#ifdef ENABLE_NANORC
625 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
626#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000627 print1opt("-K", "--keypad", _("Use alternate keypad routines"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000628#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000629 print1opt("-M", "--mac", _("Write file in Mac format"));
630 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000631#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000632#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000633 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000634#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000635#ifdef HAVE_REGEX_H
636 print1opt("-R", "--regexp", _("Do regular expression searches"));
637#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000638#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000639 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000640#endif
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000641 print1opt(_("-T [num]"), _("--tabsize=[num]"), _("Set width of a tab to num"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000642 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000643#ifdef ENABLE_COLOR
644 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
645#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000646 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000647#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000648 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
649 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000650#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000651 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000652#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000653 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000654#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000655#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000656 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000657#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000658 print1opt("-p", "--pico", _("Emulate Pico as closely as possible"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000659#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000660 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000661#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000662#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000663 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000664#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000665 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
666 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000667#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000668 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000669#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000670 print1opt("-x", "--nohelp", _("Don't show help window"));
671 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000672
673 /* this is a special case */
674 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000675
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000676 exit(0);
677}
678
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000679void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000680{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000681 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000682 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000683 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000684 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000685 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000686
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000687#ifdef DEBUG
688 printf(" --enable-debug");
689#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000690#ifdef NANO_EXTRA
691 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000692#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000693#ifdef NANO_SMALL
694 printf(" --enable-tiny");
695#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000696#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000697 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000698#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000699#ifdef DISABLE_HELP
700 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000701#endif
702#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000703 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000704#endif
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000705#if defined(DISABLE_MOUSE) || !defined(NCURSES_MOUSE_VERSION)
Chris Allegretta84de5522001-04-12 14:51:48 +0000706 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000707#endif
Chris Allegretta2a15c582002-10-25 01:51:13 +0000708#ifndef ENABLE_NLS
709 printf(" --disable-nls");
710#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000711#ifdef DISABLE_OPERATINGDIR
712 printf(" --disable-operatingdir");
713#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000714#ifdef DISABLE_SPELLER
715 printf(" --disable-speller");
716#endif
717#ifdef DISABLE_TABCOMP
718 printf(" --disable-tabcomp");
719#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000720#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000721#ifdef DISABLE_WRAPPING
722 printf(" --disable-wrapping");
723#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000724#ifdef DISABLE_ROOTWRAP
725 printf(" --disable-wrapping-as-root");
726#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000727#ifdef ENABLE_COLOR
728 printf(" --enable-color");
729#endif
730#ifdef ENABLE_MULTIBUFFER
731 printf(" --enable-multibuffer");
732#endif
733#ifdef ENABLE_NANORC
734 printf(" --enable-nanorc");
735#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000736#ifdef USE_SLANG
737 printf(" --with-slang");
738#endif
739 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000740}
741
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000742/* Stuff we do when we abort from programs and want to clean up the
743 * screen. This doesn't do much right now. */
744void do_early_abort(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000745{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000746 blank_statusbar_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000747}
748
749int no_help(void)
750{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000751 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000752}
753
Chris Allegrettad865da12002-07-29 23:46:38 +0000754#if defined(DISABLE_JUSTIFY) || defined(DISABLE_SPELLER) || defined(DISABLE_HELP) || defined(NANO_SMALL)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000755void nano_disabled_msg(void)
756{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000757 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000758}
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000759#endif
Chris Allegrettaff269f82000-12-01 18:46:01 +0000760
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000761#ifndef NANO_SMALL
762static int pid; /* This is the PID of the newly forked process
763 * below. It must be global since the signal
764 * handler needs it. */
765
766RETSIGTYPE cancel_fork(int signal)
767{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000768 if (kill(pid, SIGKILL) == -1)
769 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000770}
771
772int open_pipe(const char *command)
773{
774 int fd[2];
775 FILE *f;
776 struct sigaction oldaction, newaction;
777 /* original and temporary handlers for SIGINT */
778#ifdef _POSIX_VDISABLE
779 struct termios term, newterm;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000780#endif /* _POSIX_VDISABLE */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000781 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000782 /* cancel_sigs == 1 means that sigaction() failed without changing
783 * the signal handlers. cancel_sigs == 2 means the signal handler
784 * was changed, but the tcsetattr didn't succeed.
785 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000786 * I use this variable since it is important to put things back when
787 * we finish, even if we get errors. */
788
789 /* Make our pipes. */
790
791 if (pipe(fd) == -1) {
792 statusbar(_("Could not pipe"));
793 return 1;
794 }
795
796 /* Fork a child. */
797
798 if ((pid = fork()) == 0) {
799 close(fd[0]);
800 dup2(fd[1], fileno(stdout));
801 dup2(fd[1], fileno(stderr));
802 /* If execl() returns at all, there was an error. */
803
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000804 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000805 exit(0);
806 }
807
808 /* Else continue as parent. */
809
810 close(fd[1]);
811
812 if (pid == -1) {
813 close(fd[0]);
814 statusbar(_("Could not fork"));
815 return 1;
816 }
817
818 /* Before we start reading the forked command's output, we set
819 * things up so that ^C will cancel the new process. */
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000820 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000821 cancel_sigs = 1;
822 nperror("sigaction");
823 } else {
824 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000825 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000826 cancel_sigs = 1;
827 nperror("sigaction");
828 }
829 }
830 /* Note that now oldaction is the previous SIGINT signal handler,
831 * to be restored later. */
832
833 /* See if the platform supports disabling individual control
834 * characters. */
835#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000836 if (cancel_sigs == 0 && tcgetattr(0, &term) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000837 cancel_sigs = 2;
838 nperror("tcgetattr");
839 }
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000840 if (cancel_sigs == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000841 newterm = term;
842 /* Grab oldterm's VINTR key :-) */
843 newterm.c_cc[VINTR] = oldterm.c_cc[VINTR];
844 if (tcsetattr(0, TCSANOW, &newterm) == -1) {
845 cancel_sigs = 2;
846 nperror("tcsetattr");
847 }
848 }
849#endif /* _POSIX_VDISABLE */
850
851 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000852 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000853 nperror("fdopen");
854
855 read_file(f, "stdin", 0);
856 /* if multibuffer mode is on, we could be here in view mode; if so,
857 don't set the modification flag */
858 if (!ISSET(VIEW_MODE))
859 set_modified();
860
861 if (wait(NULL) == -1)
862 nperror("wait");
863
864#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000865 if (cancel_sigs == 0 && tcsetattr(0, TCSANOW, &term) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000866 nperror("tcsetattr");
867#endif /* _POSIX_VDISABLE */
868
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000869 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000870 nperror("sigaction");
871
872 return 0;
873}
874#endif /* NANO_SMALL */
875
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000876#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000877void do_mouse(void)
878{
879 MEVENT mevent;
880 int currslen;
881 const shortcut *s = currshortcut;
882
883 if (getmouse(&mevent) == ERR)
884 return;
885
886 /* If mouse not in edit or bottom window, return */
887 if (wenclose(edit, mevent.y, mevent.x)) {
888
889 /* Don't let people screw with the marker when they're in a
890 * subfunction. */
891 if (currshortcut != main_list)
892 return;
893
894 /* Subtract out size of topwin. Perhaps we need a constant
895 * somewhere? */
896 mevent.y -= 2;
897
898 /* Selecting where the cursor is sets the mark. Selecting
899 * beyond the line length with the cursor at the end of the line
900 * sets the mark as well. */
901 if ((mevent.y == current_y) &&
902 ((mevent.x == current_x) || (current_x == strlen(current->data)
903 && (mevent.x >
904 strlen(current->data))))) {
905 if (ISSET(VIEW_MODE)) {
906 print_view_warning();
907 return;
908 }
909 do_mark();
910 } else if (mevent.y > current_y) {
911 while (mevent.y > current_y) {
912 if (current->next != NULL)
913 current = current->next;
914 else
915 break;
916 current_y++;
917 }
918 } else if (mevent.y < current_y) {
919 while (mevent.y < current_y) {
920 if (current->prev != NULL)
921 current = current->prev;
922 else
923 break;
924 current_y--;
925 }
926 }
927 current_x = actual_x(current, mevent.x);
928 placewewant = current_x;
929 update_cursor();
930 edit_refresh();
931 } else if (wenclose(bottomwin, mevent.y, mevent.x) && !ISSET(NO_HELP)) {
932 int i, k;
933
934 if (currshortcut == main_list)
935 currslen = MAIN_VISIBLE;
936 else
937 currslen = length_of_list(currshortcut);
938
939 if (currslen < 2)
940 k = COLS / 6;
941 else
942 k = COLS / ((currslen + (currslen %2)) / 2);
943
944 /* Determine what shortcut list was clicked */
945 mevent.y -= (editwinrows + 3);
946
947 if (mevent.y < 0) /* They clicked on the statusbar */
948 return;
949
950 /* Don't select stuff beyond list length */
951 if (mevent.x / k >= currslen)
952 return;
953
954 for (i = 0; i < (mevent.x / k) * 2 + mevent.y; i++)
955 s = s->next;
956
957 /* And ungetch that value */
958 ungetch(s->val);
959
960 /* And if it's an alt-key sequence, we should probably send alt
961 too ;-) */
962 if (s->val >= 'a' && s->val <= 'z')
963 ungetch(27);
964 }
965}
966#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000967
Chris Allegretta6df90f52002-07-19 01:08:59 +0000968/* The user typed a printable character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000969void do_char(char ch)
970{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000971 size_t current_len = strlen(current->data);
972#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
973 int refresh = 0;
974 /* Do we have to run edit_refresh(), or can we get away with
975 * update_line()? */
976#endif
977
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000978 /* magic-line: when a character is inserted on the current magic line,
979 * it means we need a new one! */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000980 if (filebot == current && current->data[0] == '\0') {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000981 new_magicline();
Chris Allegretta28a0f892000-07-05 22:47:54 +0000982 fix_editbot();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000983 }
984
Chris Allegretta6df90f52002-07-19 01:08:59 +0000985 /* more dangerousness fun =) */
986 current->data = nrealloc(current->data, current_len + 2);
987 assert(current_x <= current_len);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000988 memmove(&current->data[current_x + 1],
989 &current->data[current_x],
Chris Allegretta6df90f52002-07-19 01:08:59 +0000990 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000991 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000992 totsize++;
993 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000994
Chris Allegretta6df90f52002-07-19 01:08:59 +0000995#ifndef NANO_SMALL
996 /* note that current_x has not yet been incremented */
997 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000998 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +0000999#endif
1000
Chris Allegretta6df90f52002-07-19 01:08:59 +00001001 do_right();
1002
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001003#ifndef DISABLE_WRAPPING
Chris Allegrettadffa2072002-07-24 01:02:26 +00001004 if (!ISSET(NO_WRAP) && ch != '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001005 refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001006#endif
1007
Chris Allegretta6df90f52002-07-19 01:08:59 +00001008#ifdef ENABLE_COLOR
1009 refresh = 1;
1010#endif
1011
1012#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
1013 if (refresh)
1014 edit_refresh();
1015#endif
1016
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001017 check_statblank();
1018 UNSET(KEEP_CUTBUFFER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001019}
1020
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001021int do_backspace(void)
1022{
1023 int refresh = 0;
1024 if (current_x > 0) {
1025 assert(current_x <= strlen(current->data));
1026 /* Let's get dangerous */
1027 memmove(&current->data[current_x - 1], &current->data[current_x],
1028 strlen(current->data) - current_x + 1);
1029#ifdef DEBUG
1030 fprintf(stderr, _("current->data now = \"%s\"\n"), current->data);
1031#endif
1032 align(&current->data);
1033#ifndef NANO_SMALL
1034 if (current_x <= mark_beginx && mark_beginbuf == current)
1035 mark_beginx--;
1036#endif
1037 do_left();
1038#ifdef ENABLE_COLOR
1039 refresh = 1;
1040#endif
1041 } else {
1042 filestruct *previous;
1043 const filestruct *tmp;
1044
1045 if (current == fileage)
1046 return 0; /* Can't delete past top of file */
1047
1048 previous = current->prev;
1049 current_x = strlen(previous->data);
1050 placewewant = strlenpt(previous->data);
1051#ifndef NANO_SMALL
1052 if (current == mark_beginbuf) {
1053 mark_beginx += current_x;
1054 mark_beginbuf = previous;
1055 }
1056#endif
1057 previous->data = nrealloc(previous->data,
1058 current_x + strlen(current->data) + 1);
1059 strcpy(previous->data + current_x, current->data);
1060
1061 unlink_node(current);
1062 delete_node(current);
1063 tmp = current;
1064 current = (previous->next ? previous->next : previous);
1065 renumber(current);
1066 /* We had to renumber before doing update_line. */
1067 if (tmp == edittop)
1068 page_up();
1069
1070 /* Ooops, sanity check */
1071 if (tmp == filebot) {
1072 filebot = current;
1073 editbot = current;
1074
1075 /* Recreate the magic line if we're deleting it AND if the
1076 line we're on now is NOT blank. if it is blank we
1077 can just use IT for the magic line. This is how Pico
1078 appears to do it, in any case. */
1079 if (current->data[0] != '\0') {
1080 new_magicline();
1081 fix_editbot();
1082 }
1083 }
1084
1085 current = previous;
1086 if (current_y > 0)
1087 current_y--;
1088 totlines--;
1089#ifdef DEBUG
1090 fprintf(stderr, _("After, data = \"%s\"\n"), current->data);
1091#endif
1092 UNSET(KEEP_CUTBUFFER);
1093 refresh = 1;
1094 }
1095
1096 totsize--;
1097 set_modified();
1098 if (refresh)
1099 edit_refresh();
1100 return 1;
1101}
1102
1103int do_delete(void)
1104{
1105 int refresh = 0;
1106
1107 /* blbf -> blank line before filebot (see below) */
1108 int blbf = 0;
1109
1110 if (current->next == filebot && current->data[0] == '\0')
1111 blbf = 1;
1112
1113 placewewant = xplustabs();
1114
1115 if (current_x != strlen(current->data)) {
1116 /* Let's get dangerous */
1117 memmove(&current->data[current_x], &current->data[current_x + 1],
1118 strlen(current->data) - current_x);
1119
1120 align(&current->data);
1121#ifdef ENABLE_COLOR
1122 refresh = 1;
1123#endif
1124 } else if (current->next != NULL && (current->next != filebot || blbf)) {
1125 /* We can delete the line before filebot only if it is blank: it
1126 becomes the new magic line then. */
1127
1128 filestruct *foo;
1129
1130 current->data = nrealloc(current->data,
1131 strlen(current->data) +
1132 strlen(current->next->data) + 1);
1133 strcat(current->data, current->next->data);
1134
1135 foo = current->next;
1136 if (filebot == foo) {
1137 filebot = current;
1138 editbot = current;
1139 }
1140
1141 unlink_node(foo);
1142 delete_node(foo);
1143 renumber(current);
1144 totlines--;
1145 refresh = 1;
1146 } else
1147 return 0;
1148
1149 totsize--;
1150 set_modified();
1151 UNSET(KEEP_CUTBUFFER);
1152 update_line(current, current_x);
1153 if (refresh)
1154 edit_refresh();
1155 return 1;
1156}
1157
1158int do_tab(void)
1159{
1160 do_char('\t');
1161 return 1;
1162}
1163
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001164/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001165int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001166{
Chris Allegrettae3167732001-03-18 16:59:34 +00001167 filestruct *newnode;
Chris Allegretta68532c32001-09-17 13:49:33 +00001168 char *tmp;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001169
Chris Allegretta6df90f52002-07-19 01:08:59 +00001170 newnode = make_new_node(current);
1171 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001172 tmp = &current->data[current_x];
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001173
Chris Allegrettaff989832001-09-17 13:48:00 +00001174#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001175 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001176 if (ISSET(AUTOINDENT)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001177 int extra = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001178 const char *spc = current->data;
1179
1180 while (*spc == ' ' || *spc == '\t') {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001181 extra++;
1182 spc++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001183 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001184 /* If current_x < extra, then we are breaking the line in the
1185 * indentation. Autoindenting should add only current_x
1186 * characters of indentation. */
Chris Allegrettadab017e2002-04-23 10:56:06 +00001187 if (current_x < extra)
1188 extra = current_x;
1189 else
1190 current_x = extra;
1191 totsize += extra;
1192
1193 newnode->data = charalloc(strlen(tmp) + extra + 1);
1194 strncpy(newnode->data, current->data, extra);
1195 strcpy(&newnode->data[extra], tmp);
Chris Allegrettaff989832001-09-17 13:48:00 +00001196 } else
1197#endif
1198 {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001199 current_x = 0;
Chris Allegretta88b09152001-05-17 11:35:43 +00001200 newnode->data = charalloc(strlen(tmp) + 1);
Chris Allegrettae3167732001-03-18 16:59:34 +00001201 strcpy(newnode->data, tmp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001202 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001203 *tmp = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001204
Chris Allegretta6df90f52002-07-19 01:08:59 +00001205 if (current->next == NULL) {
Chris Allegrettae3167732001-03-18 16:59:34 +00001206 filebot = newnode;
1207 editbot = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001208 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001209 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001210
1211 totsize++;
1212 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001213 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001214 align(&current->data);
1215
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001216 /* The logic here is as follows:
1217 * -> If we are at the bottom of the buffer, we want to recenter
Chris Allegretta88520c92001-05-05 17:45:54 +00001218 * (read: rebuild) the screen and forcibly move the cursor.
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001219 * -> otherwise, we want simply to redraw the screen and update
1220 * where we think the cursor is.
1221 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001222 if (current_y == editwinrows - 1) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001223#ifndef NANO_SMALL
1224 if (ISSET(SMOOTHSCROLL))
1225 edit_update(current, NONE);
1226 else
1227#endif
1228 edit_update(current, CENTER);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001229 reset_cursor();
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001230 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001231 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001232 edit_refresh();
1233 update_cursor();
1234 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001235
1236 totlines++;
1237 set_modified();
1238
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001239 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001240 return 1;
1241}
1242
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001243#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001244int do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001245{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001246 filestruct *old = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001247
Chris Allegretta6df90f52002-07-19 01:08:59 +00001248 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001249
Chris Allegretta6df90f52002-07-19 01:08:59 +00001250 /* Skip letters in this word first. */
1251 while (current->data[current_x] != '\0' &&
1252 isalnum((int)current->data[current_x]))
1253 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001254
Chris Allegretta6df90f52002-07-19 01:08:59 +00001255 for (; current != NULL; current = current->next) {
1256 while (current->data[current_x] != '\0' &&
1257 !isalnum((int)current->data[current_x]))
1258 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001259
Chris Allegretta6df90f52002-07-19 01:08:59 +00001260 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001261 break;
1262
Chris Allegretta6df90f52002-07-19 01:08:59 +00001263 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001264 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001265 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001266 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001267
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001268 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001269
Chris Allegrettad865da12002-07-29 23:46:38 +00001270 if (current->lineno >= editbot->lineno) {
1271 /* If we're on the last line, don't center the screen. */
1272 if (current->lineno == filebot->lineno)
1273 edit_refresh();
1274 else
1275 edit_update(current, CENTER);
1276 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001277 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001278 /* If we've jumped lines, refresh the old line. We can't just
1279 use current->prev here, because we may have skipped over some
1280 blank lines, in which case the previous line is the wrong
1281 one. */
1282 if (current != old) {
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001283 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001284 /* If the mark was set, then the lines between old and
1285 current have to be updated too. */
1286 if (ISSET(MARK_ISSET)) {
1287 while (old->next != current) {
1288 old = old->next;
1289 update_line(old, 0);
1290 }
1291 }
1292 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001293 update_line(current, current_x);
1294 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001295 return 0;
1296}
1297
Chris Allegretta6df90f52002-07-19 01:08:59 +00001298/* The same thing for backwards. */
1299int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001300{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001301 filestruct *old = current;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001302
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001303 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001304
Chris Allegretta6df90f52002-07-19 01:08:59 +00001305 /* Skip letters in this word first. */
1306 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1307 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001308
Chris Allegretta6df90f52002-07-19 01:08:59 +00001309 for (; current != NULL; current = current->prev) {
1310 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1311 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001312
Chris Allegretta6df90f52002-07-19 01:08:59 +00001313 if (current_x >= 0)
1314 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001315
Chris Allegretta6df90f52002-07-19 01:08:59 +00001316 if (current->prev != NULL)
1317 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001318 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001319
Chris Allegretta6df90f52002-07-19 01:08:59 +00001320 if (current != NULL) {
1321 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1322 current_x--;
1323 } else {
1324 current = fileage;
1325 current_x = 0;
1326 }
1327
Chris Allegretta76e291b2001-10-14 19:05:10 +00001328 placewewant = xplustabs();
1329
Chris Allegrettad865da12002-07-29 23:46:38 +00001330 if (current->lineno <= edittop->lineno) {
1331 /* If we're on the first line, don't center the screen. */
1332 if (current->lineno == fileage->lineno)
1333 edit_refresh();
1334 else
1335 edit_update(current, CENTER);
1336 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001337 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001338 /* If we've jumped lines, refresh the old line. We can't just
1339 use current->prev here, because we may have skipped over some
1340 blank lines, in which case the previous line is the wrong
1341 one. */
1342 if (current != old) {
Chris Allegretta76e291b2001-10-14 19:05:10 +00001343 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001344 /* If the mark was set, then the lines between old and
1345 current have to be updated too. */
1346 if (ISSET(MARK_ISSET)) {
1347 while (old->prev != current) {
1348 old = old->prev;
1349 update_line(old, 0);
1350 }
1351 }
1352 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001353 update_line(current, current_x);
1354 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001355 return 0;
1356}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001357#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001358
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001359int do_mark(void)
1360{
1361#ifdef NANO_SMALL
1362 nano_disabled_msg();
1363#else
1364 if (!ISSET(MARK_ISSET)) {
1365 statusbar(_("Mark Set"));
1366 SET(MARK_ISSET);
1367 mark_beginbuf = current;
1368 mark_beginx = current_x;
1369 } else {
1370 statusbar(_("Mark UNset"));
1371 UNSET(MARK_ISSET);
1372 edit_refresh();
1373 }
1374#endif
1375 return 1;
1376}
1377
1378void wrap_reset(void)
1379{
1380 UNSET(SAMELINEWRAP);
1381}
1382
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001383#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001384/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001385 * moved forward since the last typed character. Return value:
1386 * whether we wrapped. */
1387int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001388{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001389 size_t len = strlen(inptr->data); /* length of the line we wrap */
1390 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001391 int wrap_loc = -1; /* index of inptr->data where we wrap */
1392 int word_back = -1;
1393#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001394 const char *indentation = NULL;
1395 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001396 int indent_len = 0; /* strlen(indentation) */
1397#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001398 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001399 int after_break_len; /* strlen(after_break) */
1400 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001401 const char *wrap_line = NULL;
1402 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001403 int wrap_line_len = 0; /* strlen(wrap_line) */
1404 char *newline = NULL; /* the line we create */
1405 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001406
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001407/* There are three steps. First, we decide where to wrap. Then, we
1408 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001409
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001410/* Step 1, finding where to wrap. We are going to add a new-line
1411 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001412 * location of this replacement.
1413 *
1414 * Where should we break the line? We need the last "legal wrap point"
1415 * such that the last word before it ended at or before fill. If there
1416 * is no such point, we settle for the first legal wrap point.
1417 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001418 * A "legal wrap point" is a white-space character that is not followed by
1419 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001420 *
1421 * If there is no legal wrap point or we found the last character of the
1422 * line, we should return without wrapping.
1423 *
1424 * Note that the initial indentation does not count as a legal wrap
1425 * point if we are going to auto-indent!
1426 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001427 * Note that the code below could be optimised, by not calling strnlenpt()
1428 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001429
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001430#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001431 if (ISSET(AUTOINDENT))
1432 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001433#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001434 wrap_line = inptr->data + i;
1435 for(; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001436 /* record where the last word ended */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001437 if (*wrap_line != ' ' && *wrap_line != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001438 word_back = i;
1439 /* if we have found a "legal wrap point" and the current word
1440 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001441 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001442 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001443 /* we record the latest "legal wrap point" */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001444 if (word_back != i && wrap_line[1] != ' ' && wrap_line[1] != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001445 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001446 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001447 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001448 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001449
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001450/* Step 2, making the new wrap line. It will consist of indentation +
1451 * after_break + " " + wrap_line (although indentation and wrap_line are
1452 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001453
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001454 /* after_break is the text that will be moved to the next line. */
1455 after_break = inptr->data + wrap_loc + 1;
1456 after_break_len = len - wrap_loc - 1;
1457 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001458
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001459 /* new_line_len will later be increased by the lengths of indentation
1460 * and wrap_line. */
1461 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001462
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001463 /* We prepend the wrapped text to the next line, if the flag is set,
1464 * and there is a next line, and prepending would not make the line
1465 * too long. */
Adam Rogoyski0223d6f2000-06-17 20:36:35 +00001466 if (ISSET(SAMELINEWRAP) && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001467 wrap_line = inptr->next->data;
1468 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001469
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001470 /* +1 for the space between after_break and wrap_line */
1471 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1472 wrapping = 1;
1473 new_line_len += (1 + wrap_line_len);
1474 }
1475 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001476
Chris Allegrettaff989832001-09-17 13:48:00 +00001477#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001478 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001479 /* Indentation comes from the next line if wrapping, else from
1480 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001481 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001482 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001483 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001484 /* The wrap_line text should not duplicate indentation.
1485 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001486 wrap_line += indent_len;
1487 else
1488 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001489 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001490#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001491
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001492 /* Now we allocate the new line and copy into it. */
1493 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1494 *newline = '\0';
1495
1496#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001497 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001498 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001499 newline[indent_len] = '\0';
1500 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001501#endif
1502 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001503 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001504 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001505 null_at(&inptr->data, wrap_loc + 1);
1506 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001507 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001508 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001509 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001510 * in a tab or a space, we don't add a space and decrement
1511 * totsize to account for that. */
David Lawrence Ramsey7c4222c2002-09-26 22:49:56 +00001512 if (!isspace(newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001513 strcat(newline, " ");
1514 else
1515 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001516 strcat(newline, wrap_line);
1517 free(inptr->next->data);
1518 inptr->next->data = newline;
1519 } else {
1520 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001521
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001522 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001523 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001524#ifndef NANO_SMALL
1525 totsize += indent_len;
1526#endif
1527 totlines++;
1528 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001529 temp->prev = inptr;
1530 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001531 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001532 /* If temp->next is NULL, then temp is the last line of the
1533 * file, so we must set filebot. */
1534 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001535 temp->next->prev = temp;
1536 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001537 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001538 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001539
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001540/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1541 * other sundry things. */
1542
1543 /* later wraps of this line will be prepended to the next line. */
1544 SET(SAMELINEWRAP);
1545
1546 /* Each line knows its line number. We recalculate these if we
1547 * inserted a new line. */
1548 if (!wrapping)
1549 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001550
Chris Allegretta6df90f52002-07-19 01:08:59 +00001551 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001552 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001553 current = current->next;
1554 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001555#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001556 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001557#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001558 wrap_loc + 1;
1559 wrap_reset();
1560 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001561 }
1562
Chris Allegretta6df90f52002-07-19 01:08:59 +00001563#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001564 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001565 * If it was on the next line and we wrapped, we must move it
1566 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001567 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1568 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001569 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001570 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001571 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001572#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001573
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001574 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001575 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001576
1577 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001578}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001579#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001580
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001581#ifndef DISABLE_SPELLER
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001582int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001583{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001584 char *save_search;
1585 char *save_replace;
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001586 filestruct *begin;
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001587 int i = 0, j = 0, beginx, beginx_top, reverse_search_set, case_sens_set;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001588#ifndef NANO_SMALL
1589 int mark_set;
1590#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001591
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001592 /* save where we are */
1593 begin = current;
1594 beginx = current_x + 1;
1595
Chris Allegretta23b74b22002-01-21 20:32:22 +00001596 /* Make sure Spell Check goes forward only */
1597 reverse_search_set = ISSET(REVERSE_SEARCH);
1598 UNSET(REVERSE_SEARCH);
1599
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001600 case_sens_set = ISSET(CASE_SENSITIVE);
1601 SET(CASE_SENSITIVE);
1602
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001603#ifndef NANO_SMALL
1604 /* Make sure the marking highlight is off during Spell Check */
1605 mark_set = ISSET(MARK_ISSET);
1606 UNSET(MARK_ISSET);
1607#endif
1608
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001609 /* save the current search/replace strings */
1610 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001611 save_search = last_search;
1612 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001613
1614 /* set search/replace strings to mis-spelt word */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001615 last_search = mallocstrcpy(NULL, word);
1616 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001617
1618 /* start from the top of file */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001619 current = fileage;
1620 current_x = beginx_top = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001621
1622 search_last_line = FALSE;
1623
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001624 while (1) {
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001625 /* make sure word is still mis-spelt (i.e. when multi-errors) */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001626 if (findnextstr(TRUE, FALSE, fileage, beginx_top, word)) {
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001627
Chris Allegretta6df90f52002-07-19 01:08:59 +00001628 /* find whole words only */
1629 if (!is_whole_word(current_x, current->data, word))
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001630 continue;
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001631
Chris Allegrettabfd2f562002-12-10 03:03:20 +00001632 edit_update(current, current_x);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001633 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001634
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001635 /* allow replace word to be corrected */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001636 i = statusq(0, spell_list, last_replace, _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001637
Chris Allegretta6df90f52002-07-19 01:08:59 +00001638 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001639
1640 /* start from the start of this line again */
1641 current = fileage;
1642 current_x = beginx_top;
1643
1644 search_last_line = FALSE;
1645
Chris Allegretta6df90f52002-07-19 01:08:59 +00001646 if (strcmp(word, answer)) {
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001647 j = i;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001648 do_replace_loop(word, fileage, &beginx_top, TRUE, &j);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001649 }
Chris Allegretta80838272001-12-02 06:03:22 +00001650 }
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001651 break;
Rocco Corsi562964d2002-01-13 03:18:03 +00001652 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001653
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001654 /* restore the search/replace strings */
Chris Allegrettabef12972002-03-06 03:30:40 +00001655 free(last_search); last_search=save_search;
1656 free(last_replace); last_replace=save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001657
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001658 /* restore where we were */
1659 current = begin;
1660 current_x = beginx - 1;
1661
Chris Allegretta23b74b22002-01-21 20:32:22 +00001662 /* restore Search/Replace direction */
1663 if (reverse_search_set)
1664 SET(REVERSE_SEARCH);
1665
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001666 if (!case_sens_set)
1667 UNSET(CASE_SENSITIVE);
1668
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001669#ifndef NANO_SMALL
1670 /* restore marking highlight */
1671 if (mark_set)
1672 SET(MARK_ISSET);
1673#endif
1674
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001675 if (i == -1)
1676 return FALSE;
1677
1678 return TRUE;
1679}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001680
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001681/* Integrated spell checking using 'spell' program. Return value: NULL
1682 * for normal termination, otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001683char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001684{
Chris Allegretta271e9722000-11-10 18:15:43 +00001685 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001686 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001687 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd;
1688 pid_t pid_spell, pid_sort, pid_uniq;
1689 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001690
Chris Allegretta334a9402002-12-16 04:25:53 +00001691 char *pipe_msg = _("Could not create pipe");
Chris Allegretta271e9722000-11-10 18:15:43 +00001692 /* Create a pipe to spell program */
1693
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001694 if (pipe(spell_fd) == -1)
Chris Allegretta334a9402002-12-16 04:25:53 +00001695 return pipe_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001696
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001697 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegretta271e9722000-11-10 18:15:43 +00001698 /* A new process to run spell in */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001699
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001700 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001701
1702 /* Child continues, (i.e. future spell process) */
1703
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001704 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001705
Chris Allegretta271e9722000-11-10 18:15:43 +00001706 /* replace the standard in with the tempfile */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001707 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1) {
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001708 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001709 exit(1);
1710 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001711 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001712 close(tempfile_fd);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001713 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001714 exit(1);
1715 }
1716 close(tempfile_fd);
1717
1718 /* send spell's standard out to the pipe */
1719
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001720 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
1721 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001722 exit(1);
1723 }
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001724 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001725
1726 /* Start spell program, we are using the PATH here!?!? */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001727 execlp("spell", "spell", NULL);
1728
Chris Allegretta271e9722000-11-10 18:15:43 +00001729 /* Should not be reached, if spell is found!!! */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001730
Chris Allegretta271e9722000-11-10 18:15:43 +00001731 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001732 }
1733
1734 /* Parent continues here */
1735
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001736 close(spell_fd[1]);
1737
1738 if (pipe(sort_fd) == -1)
Chris Allegretta334a9402002-12-16 04:25:53 +00001739 return pipe_msg;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001740
1741 /* A new process to run sort in */
1742
1743 if ((pid_sort = fork()) == 0) {
1744
1745 /* Child continues, (i.e. future spell process) */
1746 /* replace the standard in with output of the old pipe */
1747 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO) {
1748 close(spell_fd[0]);
1749 close(sort_fd[1]);
1750 exit(1);
1751 }
1752 close(spell_fd[0]);
1753
1754 /* send sort's standard out to the new pipe */
1755
1756 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
1757 close(sort_fd[1]);
1758 exit(1);
1759 }
1760 close(sort_fd[1]);
1761
1762 /* Start sort program. Use -f to remove mixed case without having
1763 to have ANOTHER pipe for tr. If this isn't portable, let me know. */
1764 execlp("sort", "sort", "-f", NULL);
1765
1766 /* Should not be reached, if sort is found */
1767
1768 exit(1);
1769 }
1770
1771 close(sort_fd[1]);
1772
1773 /* And one more for uniq! */
1774
1775 if (pipe(uniq_fd) == -1)
Chris Allegretta334a9402002-12-16 04:25:53 +00001776 return pipe_msg;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001777
1778 /* A new process to run uniq in */
1779
1780 if ((pid_uniq = fork()) == 0) {
1781
1782 /* Child continues, (i.e. future uniq process) */
1783 /* replace the standard in with output of the old pipe */
1784 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO) {
1785 close(sort_fd[0]);
1786 close(uniq_fd[1]);
1787 exit(1);
1788 }
1789 close(sort_fd[0]);
1790
1791 /* send uniq's standard out to the new pipe */
1792
1793 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
1794 close(uniq_fd[1]);
1795 exit(1);
1796 }
1797 close(uniq_fd[1]);
1798
1799 /* Start uniq program, we are using PATH */
1800 execlp("uniq", "uniq", NULL);
1801
1802 /* Should not be reached, if uniq is found */
1803
1804 exit(1);
1805 }
1806
1807 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001808
1809 /* Child process was not forked successfully */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001810
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001811 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1812 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001813 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001814 }
1815
Chris Allegretta271e9722000-11-10 18:15:43 +00001816 /* Get system pipe buffer size */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001817
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001818 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1819 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001820 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001821 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001822
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001823 /* Read-in the returned spelling errors */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001824
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001825 read_buff_read = 0;
1826 read_buff_size = pipe_buff_size + 1;
1827 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001828
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001829 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001830 read_buff_read += bytesread;
1831 read_buff_size += pipe_buff_size;
1832 read_buff = read_buff_ptr = nrealloc(read_buff, read_buff_size);
1833 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001834
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001835 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001836
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001837 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001838 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001839
1840 /* Process the spelling errors */
1841
1842 read_buff_word = read_buff_ptr = read_buff;
1843
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001844 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001845
1846 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001847 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001848 if (read_buff_word != read_buff_ptr) {
1849 if (!do_int_spell_fix(read_buff_word)) {
1850 read_buff_word = read_buff_ptr;
1851 break;
1852 }
1853 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001854 read_buff_word = read_buff_ptr + 1;
1855 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001856 read_buff_ptr++;
1857 }
1858
1859 /* special case where last word doesn't end with \n or \r */
1860 if (read_buff_word != read_buff_ptr)
1861 do_int_spell_fix(read_buff_word);
1862
Chris Allegretta271e9722000-11-10 18:15:43 +00001863 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001864 replace_abort();
Chris Allegretta35908f82002-12-10 00:55:32 +00001865 edit_update(current, current_x);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001866
Chris Allegretta271e9722000-11-10 18:15:43 +00001867 /* Process end of spell process */
1868
Chris Allegretta334a9402002-12-16 04:25:53 +00001869 waitpid(pid_spell, &spell_status, 0);
1870 waitpid(pid_sort, &sort_status, 0);
1871 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001872
Chris Allegretta334a9402002-12-16 04:25:53 +00001873 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1874 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001875
Chris Allegretta334a9402002-12-16 04:25:53 +00001876 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1877 return _("Error invoking \"sort -f\"");
1878
1879 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1880 return _("Error invoking \"uniq\"");
1881
1882 /* Otherwise... */
1883 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001884}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001885
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001886/* External spell checking. Return value: NULL for normal termination,
1887 * otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001888char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001889{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001890 int alt_spell_status, lineno_cur = current->lineno;
1891 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001892 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001893 char *ptr;
1894 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001895 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001896#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001897 int mark_set = ISSET(MARK_ISSET);
1898 int mbb_lineno_cur = 0;
1899 /* We're going to close the current file, and open the output of
1900 the alternate spell command. The line that mark_beginbuf
1901 points to will be freed, so we save the line number and restore
1902 afterwards. */
1903
1904 if (mark_set) {
1905 mbb_lineno_cur = mark_beginbuf->lineno;
1906 UNSET(MARK_ISSET);
1907 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001908#endif
1909
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001910 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001911
Chris Allegrettae434b452001-01-27 19:25:00 +00001912 /* Set up an argument list to pass the execvp function */
1913 if (spellargs == NULL) {
1914 spellargs = nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001915
Chris Allegrettae434b452001-01-27 19:25:00 +00001916 spellargs[0] = strtok(alt_speller, " ");
1917 while ((ptr = strtok(NULL, " ")) != NULL) {
1918 arglen++;
1919 spellargs = nrealloc(spellargs, arglen * sizeof(char *));
1920 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001921 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001922 spellargs[arglen - 1] = NULL;
1923 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001924 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001925
1926 /* Start a new process for the alternate speller */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001927 if ((pid_spell = fork()) == 0) {
Chris Allegretta88520c92001-05-05 17:45:54 +00001928 /* Start alternate spell program; we are using the PATH here!?!? */
Chris Allegretta169ee842001-01-26 01:57:32 +00001929 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001930
1931 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001932 exit(1);
1933 }
1934
1935 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001936 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001937 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001938
1939 /* Wait for alternate speller to complete */
1940
1941 wait(&alt_spell_status);
Chris Allegretta334a9402002-12-16 04:25:53 +00001942 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1943 char *altspell_error = NULL;
1944 char *invoke_error = _("Could not invoke \"%s\"");
1945 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1946
1947 altspell_error = charalloc(msglen);
1948 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1949 return altspell_error;
1950 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001951
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001952 refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001953 free_filestruct(fileage);
Chris Allegretta56214c62001-09-27 02:46:53 +00001954 global_init(1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001955 open_file(tempfile_name, 0, 1);
Rocco Corsi4dfaf932001-04-20 01:59:55 +00001956
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001957#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001958 if (mark_set) {
1959 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1960 mark_beginbuf = current;
1961 mark_beginx = current_x;
1962 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001963 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001964 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001965#endif
1966
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001967 /* go back to the old position, mark the file as modified, and make
1968 sure that the titlebar is refreshed */
1969 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001970 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001971 clearok(topwin, FALSE);
1972 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001973
Chris Allegretta334a9402002-12-16 04:25:53 +00001974 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001975}
1976#endif
1977
1978int do_spell(void)
1979{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001980#ifdef DISABLE_SPELLER
Chris Allegrettaff269f82000-12-01 18:46:01 +00001981 nano_disabled_msg();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001982 return TRUE;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001983#else
Chris Allegretta334a9402002-12-16 04:25:53 +00001984 char *temp, *spell_msg = _("Generic error");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001985
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001986 if ((temp = safe_tempnam(0, "nano.")) == NULL) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001987 statusbar(_("Could not create a temporary filename: %s"),
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001988 strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001989 return 0;
1990 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001991
Chris Allegrettaecc3d7f2001-06-05 23:24:55 +00001992 if (write_file(temp, 1, 0, 0) == -1) {
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001993 statusbar(_("Spell checking failed: unable to write temp file!"));
Chris Allegrettabef12972002-03-06 03:30:40 +00001994 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001995 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001996 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001997
Chris Allegrettae1f14522001-09-19 03:19:43 +00001998#ifdef ENABLE_MULTIBUFFER
1999 /* update the current open_files entry before spell-checking, in case
Chris Allegretta4dc03d52002-05-11 03:04:44 +00002000 any problems occur */
Chris Allegretta48b06702002-02-22 04:30:50 +00002001 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00002002#endif
2003
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002004 if (alt_speller != NULL)
Chris Allegretta334a9402002-12-16 04:25:53 +00002005 spell_msg = do_alt_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00002006 else
Chris Allegretta334a9402002-12-16 04:25:53 +00002007 spell_msg = do_int_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00002008 remove(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002009
Chris Allegretta334a9402002-12-16 04:25:53 +00002010 if (spell_msg == NULL) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002011 statusbar(_("Finished checking spelling"));
Chris Allegretta334a9402002-12-16 04:25:53 +00002012 return 1;
2013 } else {
2014 statusbar(_("Spell checking failed: %s"), spell_msg);
2015 return 0;
2016 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002017
Chris Allegrettabef12972002-03-06 03:30:40 +00002018 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002019
Chris Allegrettadbc12b22000-07-03 03:10:14 +00002020#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00002021}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002022
Chris Allegrettad865da12002-07-29 23:46:38 +00002023#if !defined(DISABLE_WRAPPING) && !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002024/* The "indentation" of a line is the white-space between the quote part
2025 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002026size_t indent_length(const char *line)
2027{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002028 size_t len = 0;
2029
2030 assert(line != NULL);
2031 while (*line == ' ' || *line == '\t') {
2032 line++;
2033 len++;
2034 }
2035 return len;
2036}
Chris Allegrettadffa2072002-07-24 01:02:26 +00002037#endif /* !DISABLE_WRAPPING && !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002038
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002039#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00002040/* justify_format() replaces Tab by Space and multiple spaces by 1 (except
2041 * it maintains 2 after a . ! or ?). Note the terminating \0
2042 * counts as a space.
2043 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002044 * If !changes_allowed and justify_format() needs to make a change, it
Chris Allegretta6df90f52002-07-19 01:08:59 +00002045 * returns 1, otherwise returns 0.
2046 *
2047 * If changes_allowed, justify_format() might make line->data
2048 * shorter, and change the actual pointer with null_at().
2049 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002050 * justify_format() will not look at the first skip characters of line.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002051 * skip should be at most strlen(line->data). The skip+1st character must
2052 * not be whitespace. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002053int justify_format(int changes_allowed, filestruct *line, size_t skip)
2054{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002055 const char *punct = ".?!";
2056 const char *brackets = "'\")}]>";
Chris Allegretta6df90f52002-07-19 01:08:59 +00002057 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002058
Chris Allegretta6df90f52002-07-19 01:08:59 +00002059 /* These four asserts are assumptions about the input data. */
2060 assert(line != NULL);
2061 assert(line->data != NULL);
2062 assert(skip <= strlen(line->data));
2063 assert(line->data[skip] != ' ' && line->data[skip] != '\t');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002064
Chris Allegretta6df90f52002-07-19 01:08:59 +00002065 back = line->data + skip;
2066 front = back;
2067 for (; *front; front++) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002068 int remove_space = 0;
2069 /* Do we want to remove this space? */
2070
Chris Allegretta6df90f52002-07-19 01:08:59 +00002071 if (*front == '\t') {
2072 if (!changes_allowed)
2073 return 1;
2074 *front = ' ';
2075 }
2076 /* these tests are safe since line->data + skip is not a space */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002077 if (*front == ' ' && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002078 const char *bob = front - 2;
2079
2080 remove_space = 1;
2081 for (bob = front - 2; bob >= line->data + skip; bob--) {
2082 if (strchr(punct, *bob) != NULL) {
2083 remove_space = 0;
2084 break;
2085 }
2086 if (strchr(brackets, *bob) == NULL)
2087 break;
2088 }
2089 }
2090
2091 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002092 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002093 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002094 if (!changes_allowed)
2095 return 1;
2096#ifndef NANO_SMALL
2097 if (mark_beginbuf == line && back - line->data < mark_beginx)
2098 mark_beginx--;
2099#endif
2100 } else {
2101 *back = *front;
2102 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002103 }
2104 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002105
2106 /* Remove spaces from the end of the line, except maintain 1 after a
2107 * sentence punctuation. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002108 while (line->data < back && *(back - 1) == ' ')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002109 back--;
2110 if (line->data < back && *back == ' ' &&
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002111 strchr(punct, *(back - 1)) != NULL)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002112 back++;
2113 if (!changes_allowed && back != front)
2114 return 1;
2115
2116 /* This assert merely documents a fact about the loop above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002117 assert(changes_allowed != 0 || back == front);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002118
2119 /* Now back is the new end of line->data. */
2120 if (back != front) {
2121 totsize += back - line->data - strlen(line->data);
2122 null_at(&line->data, back - line->data);
2123#ifndef NANO_SMALL
2124 if (mark_beginbuf == line && back - line->data < mark_beginx)
2125 mark_beginx = back - line->data;
2126#endif
2127 }
2128 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002129}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002130
2131/* The "quote part" of a line is the largest initial substring matching
2132 * the quote string. This function returns the length of the quote part
2133 * of the given line.
2134 *
2135 * Note that if !HAVE_REGEX_H then we match concatenated copies of
2136 * quotestr. */
2137#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002138size_t quote_length(const char *line, const regex_t *qreg)
2139{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002140 regmatch_t matches;
2141 int rc = regexec(qreg, line, 1, &matches, 0);
2142
2143 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
2144 return 0;
2145 /* matches.rm_so should be 0, since the quote string should start with
2146 * the caret ^. */
2147 return matches.rm_eo;
2148}
2149#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002150size_t quote_length(const char *line)
2151{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002152 size_t qdepth = 0;
2153 size_t qlen = strlen(quotestr);
2154
2155 /* Compute quote depth level */
2156 while (!strcmp(line + qdepth, quotestr))
2157 qdepth += qlen;
2158 return qdepth;
2159}
2160#endif /* !HAVE_REGEX_H */
2161
Chris Allegretta6df90f52002-07-19 01:08:59 +00002162/* a_line and b_line are lines of text. The quotation part of a_line is
2163 * the first a_quote characters. Check that the quotation part of
2164 * b_line is the same. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002165int quotes_match(const char *a_line, size_t a_quote,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002166 IFREG(const char *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002167{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002168 /* Here is the assumption about a_quote: */
2169 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00002170 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00002171 !strncmp(a_line, b_line, a_quote);
2172}
2173
2174/* We assume a_line and b_line have no quote part. Then, we return whether
2175 * b_line could follow a_line in a paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002176size_t indents_match(const char *a_line, size_t a_indent,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002177 const char *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002178{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002179 assert(a_indent == indent_length(a_line));
2180 assert(b_indent == indent_length(b_line));
2181
2182 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2183}
2184
2185/* Put the next par_len lines, starting with first_line, in the cut
2186 * buffer. We assume there are enough lines after first_line. We leave
2187 * copies of the lines in place, too. We return the new copy of
2188 * first_line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002189filestruct *backup_lines(filestruct *first_line, size_t par_len,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002190 size_t quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002191{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002192 /* We put the original lines, not copies, into the cut buffer, just
2193 * out of a misguided sense of consistency, so if you un-cut, you
2194 * get the actual same paragraph back, not a copy. */
2195 filestruct *alice = first_line;
2196
2197 set_modified();
2198 cutbuffer = NULL;
2199 for(; par_len > 0; par_len--) {
2200 filestruct *bob = copy_node(alice);
2201
2202 if (alice == first_line)
2203 first_line = bob;
2204 if (alice == current)
2205 current = bob;
2206 if (alice == edittop)
2207 edittop = bob;
2208#ifndef NANO_SMALL
2209 if (alice == mark_beginbuf)
2210 mark_beginbuf = bob;
2211#endif
2212 justify_format(1, bob,
2213 quote_len + indent_length(bob->data + quote_len));
2214
2215 assert(alice != NULL && bob != NULL);
2216 add_to_cutbuffer(alice);
2217 splice_node(bob->prev, bob, bob->next);
2218 alice = bob->next;
2219 }
2220 return first_line;
2221}
2222
2223/* We are trying to break a chunk off line. We find the last space such
2224 * that the display length to there is at most goal + 1. If there is
2225 * no such space, and force is not 0, then we find the first space.
2226 * Anyway, we then take the last space in that group of spaces. The
2227 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002228int break_line(const char *line, int goal, int force)
2229{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002230 /* Note that we use int instead of size_t, since goal is at most COLS,
2231 * the screen width, which will always be reasonably small. */
2232 int space_loc = -1;
2233 /* Current tentative return value. Index of the last space we
2234 * found with short enough display width. */
2235 int cur_loc = 0;
2236 /* Current index in line */
2237
2238 assert(line != NULL);
2239 for(; *line != '\0' && goal >= 0; line++, cur_loc++) {
2240 if (*line == ' ')
2241 space_loc = cur_loc;
2242 assert(*line != '\t');
2243
Chris Allegrettacf287c82002-07-20 13:57:41 +00002244 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002245 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002246 else
2247 goal--;
2248 }
2249 if (goal >= 0)
2250 /* In fact, the whole line displays shorter than goal. */
2251 return cur_loc;
2252 if (space_loc == -1) {
2253 /* No space found short enough. */
2254 if (force)
2255 for(; *line != '\0'; line++, cur_loc++)
2256 if (*line == ' ' && *(line + 1) != ' ')
2257 return cur_loc;
2258 return -1;
2259 }
2260 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002261 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002262 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2263 *(line - cur_loc + space_loc + 1) == '\0')
2264 space_loc++;
2265 return space_loc;
2266}
2267#endif /* !DISABLE_JUSTIFY */
2268
2269/* This function justifies the current paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002270int do_justify(void)
2271{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002272#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +00002273 nano_disabled_msg();
2274 return 1;
2275#else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002276
Chris Allegretta6df90f52002-07-19 01:08:59 +00002277/* To explain the justifying algorithm, I first need to define some
2278 * phrases about paragraphs and quotation:
2279 * A line of text consists of a "quote part", followed by an
2280 * "indentation part", followed by text. The functions quote_length()
2281 * and indent_length() calculate these parts.
2282 *
2283 * A line is "part of a paragraph" if it has a part not in the quote
2284 * part or the indentation.
2285 *
2286 * A line is "the beginning of a paragraph" if it is part of a paragraph
2287 * and
2288 * 1) it is the top line of the file, or
2289 * 2) the line above it is not part of a paragraph, or
2290 * 3) the line above it does not have precisely the same quote
2291 * part, or
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002292 * 4) the indentation of this line is not an initial substring of the
Chris Allegretta6df90f52002-07-19 01:08:59 +00002293 * indentation of the previous line, or
2294 * 5) this line has no quote part and some indentation, and
2295 * AUTOINDENT is not set.
2296 * The reason for number 5) is that if AUTOINDENT is not set, then an
2297 * indented line is expected to start a paragraph, like in books. Thus,
2298 * nano can justify an indented paragraph only if AUTOINDENT is turned
2299 * on.
2300 *
2301 * A contiguous set of lines is a "paragraph" if each line is part of
2302 * a paragraph and only the first line is the beginning of a paragraph.
Chris Allegrettad4fa0d32002-03-05 19:55:55 +00002303 */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002304
Chris Allegretta6df90f52002-07-19 01:08:59 +00002305 size_t quote_len;
2306 /* Length of the initial quotation of the paragraph we justify. */
2307 size_t par_len;
2308 /* Number of lines in that paragraph. */
2309 filestruct *first_mod_line = NULL;
2310 /* Will be the first line of the resulting justified paragraph
2311 * that differs from the original. For restoring after uncut. */
2312 filestruct *last_par_line = current;
2313 /* Will be the last line of the result, also for uncut. */
2314 filestruct *cutbuffer_save = cutbuffer;
2315 /* When the paragraph gets modified, all lines from the changed
2316 * one down are stored in the cut buffer. We back up the original
2317 * to restore it later. */
2318
2319 /* We save these global variables to be restored if the user
2320 * unjustifies. Note we don't need to save totlines. */
2321 int current_x_save = current_x;
2322 int current_y_save = current_y;
2323 filestruct *current_save = current;
2324 int flags_save = flags;
2325 long totsize_save = totsize;
2326 filestruct *edittop_save = edittop;
2327 filestruct *editbot_save = editbot;
2328#ifndef NANO_SMALL
2329 filestruct *mark_beginbuf_save = mark_beginbuf;
2330 int mark_beginx_save = mark_beginx;
2331#endif
2332
2333 size_t indent_len; /* generic indentation length */
2334 filestruct *line; /* generic line of text */
2335 size_t i; /* generic loop variable */
2336
2337#ifdef HAVE_REGEX_H
2338 regex_t qreg; /* qreg is the compiled quotation regexp.
Chris Allegrettad865da12002-07-29 23:46:38 +00002339 * We no longer care about quotestr. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002340 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2341
2342 if (rc) {
2343 size_t size = regerror(rc, &qreg, NULL, 0);
2344 char *strerror = charalloc(size);
2345
2346 regerror(rc, &qreg, strerror, size);
2347 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2348 free(strerror);
2349 return -1;
2350 }
2351#endif
2352
2353 /* Here is an assumption that is always true anyway. */
2354 assert(current != NULL);
2355
2356/* Here we find the first line of the paragraph to justify. If the
2357 * current line is in a paragraph, then we move back to the first line.
2358 * Otherwise we move down to the first line that is in a paragraph. */
2359 quote_len = quote_length(IFREG(current->data, &qreg));
2360 indent_len = indent_length(current->data + quote_len);
2361
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002362 current_x = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002363 if (current->data[quote_len + indent_len] != '\0') {
2364 /* This line is part of a paragraph. So we must search back to
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002365 * the first line of this paragraph. First we check items 1) and
2366 * 3) above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002367 while (current->prev != NULL && quotes_match(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002368 quote_len, IFREG(current->prev->data, &qreg))) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002369 size_t temp_id_len =
Chris Allegretta6df90f52002-07-19 01:08:59 +00002370 indent_length(current->prev->data + quote_len);
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002371 /* The indentation length of the previous line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002372
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002373 /* Is this line the beginning of a paragraph, according to
2374 items 2), 5), or 4) above? If so, stop. */
2375 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
2376 (quote_len == 0 && indent_len > 0
2377#ifndef NANO_SMALL
2378 && !ISSET(AUTOINDENT)
2379#endif
2380 ) ||
2381 !indents_match(current->prev->data + quote_len,
2382 temp_id_len, current->data + quote_len, indent_len))
2383 break;
2384 indent_len = temp_id_len;
2385 current = current->prev;
2386 current_y--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00002387 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002388 } else {
Chris Allegrettad865da12002-07-29 23:46:38 +00002389 /* This line is not part of a paragraph. Move down until we get
2390 * to a non "blank" line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002391 do {
2392 /* There is no next paragraph, so nothing to justify. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002393 if (current->next == NULL) {
2394 placewewant = 0;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002395 if (current_y > editwinrows - 1)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002396 edit_update(current, CENTER);
2397 else
2398 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002399 return 0;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002400 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002401 current = current->next;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002402 current_y++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002403 quote_len = quote_length(IFREG(current->data, &qreg));
2404 indent_len = indent_length(current->data + quote_len);
2405 } while (current->data[quote_len + indent_len] == '\0');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002406 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002407/* Now current is the first line of the paragraph, and quote_len
2408 * is the quotation length of that line. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002409
Chris Allegretta6df90f52002-07-19 01:08:59 +00002410/* Next step, compute par_len, the number of lines in this paragraph. */
2411 line = current;
2412 par_len = 1;
2413 indent_len = indent_length(line->data + quote_len);
2414
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002415 while (line->next != NULL && quotes_match(current->data, quote_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002416 IFREG(line->next->data, &qreg))) {
2417 size_t temp_id_len = indent_length(line->next->data + quote_len);
2418
2419 if (!indents_match(line->data + quote_len, indent_len,
2420 line->next->data + quote_len, temp_id_len) ||
2421 line->next->data[quote_len + temp_id_len] == '\0' ||
2422 (quote_len == 0 && temp_id_len > 0
2423#ifndef NANO_SMALL
2424 && !ISSET(AUTOINDENT)
2425#endif
2426 ))
2427 break;
2428 indent_len = temp_id_len;
2429 line = line->next;
2430 par_len++;
2431 }
2432#ifdef HAVE_REGEX_H
2433 /* We no longer need to check quotation. */
2434 regfree(&qreg);
2435#endif
2436/* Now par_len is the number of lines in this paragraph. Should never
2437 * call quotes_match() or quote_length() again. */
2438
2439/* Next step, we loop through the lines of this paragraph, justifying
2440 * each one individually. */
2441 for(; par_len > 0; current_y++, par_len--) {
2442 size_t line_len;
2443 size_t display_len;
2444 /* The width of current in screen columns. */
2445 int break_pos;
2446 /* Where we will break the line. */
2447
2448 indent_len = indent_length(current->data + quote_len) +
2449 quote_len;
2450 /* justify_format() removes excess spaces from the line, and
2451 * changes tabs to spaces. The first argument, 0, means don't
2452 * change the line, just say whether there are changes to be
2453 * made. If there are, we do backup_lines(), which copies the
2454 * original paragraph to the cutbuffer for unjustification, and
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002455 * then calls justify_format() on the remaining lines. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002456 if (first_mod_line == NULL && justify_format(0, current, indent_len))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002457 first_mod_line = backup_lines(current, par_len, quote_len);
2458
2459 line_len = strlen(current->data);
2460 display_len = strlenpt(current->data);
2461
2462 if (display_len > fill) {
2463 /* The line is too long. Try to wrap it to the next. */
2464 break_pos = break_line(current->data + indent_len,
2465 fill - strnlenpt(current->data, indent_len),
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002466 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002467 if (break_pos == -1 || break_pos + indent_len == line_len)
2468 /* We can't break the line, or don't need to, so just go
2469 * on to the next. */
2470 goto continue_loc;
2471 break_pos += indent_len;
2472 assert(break_pos < line_len);
2473 /* If we haven't backed up the paragraph, do it now. */
2474 if (first_mod_line == NULL)
2475 first_mod_line = backup_lines(current, par_len, quote_len);
2476 if (par_len == 1) {
2477 /* There is no next line in this paragraph. We make a new
2478 * line and copy text after break_pos into it. */
2479 splice_node(current, make_new_node(current),
2480 current->next);
2481 current->next->data = charalloc(indent_len + line_len -
2482 break_pos);
2483 strncpy(current->next->data, current->data,
2484 indent_len);
2485 strcpy(current->next->data + indent_len,
2486 current->data + break_pos + 1);
2487 assert(strlen(current->next->data) ==
2488 indent_len + line_len - break_pos - 1);
2489 totlines++;
2490 totsize += indent_len;
2491 par_len++;
2492 } else {
2493 size_t next_line_len = strlen(current->next->data);
2494
2495 indent_len = quote_len +
2496 indent_length(current->next->data + quote_len);
2497 current->next->data = (char *)nrealloc(current->next->data,
2498 sizeof(char) * (next_line_len + line_len -
2499 break_pos + 1));
2500
2501 memmove(current->next->data + indent_len + line_len - break_pos,
2502 current->next->data + indent_len,
2503 next_line_len - indent_len + 1);
2504 strcpy(current->next->data + indent_len,
2505 current->data + break_pos + 1);
2506 current->next->data[indent_len + line_len - break_pos - 1]
2507 = ' ';
2508#ifndef NANO_SMALL
2509 if (mark_beginbuf == current->next) {
2510 if (mark_beginx < indent_len)
2511 mark_beginx = indent_len;
2512 mark_beginx += line_len - break_pos;
2513 }
2514#endif
2515 }
2516#ifndef NANO_SMALL
2517 if (mark_beginbuf == current && mark_beginx > break_pos) {
2518 mark_beginbuf = current->next;
2519 mark_beginx -= break_pos + 1 - indent_len;
2520 }
2521#endif
2522 null_at(&current->data, break_pos);
2523 current = current->next;
2524 } else if (display_len < fill && par_len > 1) {
2525 size_t next_line_len = strlen(current->next->data);
2526
2527 indent_len = quote_len +
2528 indent_length(current->next->data + quote_len);
2529 break_pos = break_line(current->next->data + indent_len,
2530 fill - display_len - 1, 0);
2531 if (break_pos == -1)
2532 /* We can't pull a word from the next line up to this one,
2533 * so just go on. */
2534 goto continue_loc;
2535
2536 /* If we haven't backed up the paragraph, do it now. */
2537 if (first_mod_line == NULL)
2538 first_mod_line = backup_lines(current, par_len, quote_len);
2539 current->data = (char *)nrealloc(current->data,
2540 line_len + break_pos + 2);
2541 current->data[line_len] = ' ';
2542 strncpy(current->data + line_len + 1,
2543 current->next->data + indent_len, break_pos);
2544 current->data[line_len + break_pos + 1] = '\0';
2545#ifndef NANO_SMALL
2546 if (mark_beginbuf == current->next) {
2547 if (mark_beginx < indent_len + break_pos) {
2548 mark_beginbuf = current;
2549 if (mark_beginx <= indent_len)
2550 mark_beginx = line_len + 1;
2551 else
2552 mark_beginx = line_len + 1 + mark_beginx - indent_len;
2553 } else
2554 mark_beginx -= break_pos + 1;
2555 }
2556#endif
2557 if (indent_len + break_pos == next_line_len) {
2558 line = current->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002559
2560 /* Don't destroy edittop! */
2561 if (line == edittop)
2562 edittop = current;
2563
Chris Allegretta6df90f52002-07-19 01:08:59 +00002564 unlink_node(line);
2565 delete_node(line);
2566 totlines--;
2567 totsize -= indent_len;
2568 current_y--;
2569 } else {
2570 memmove(current->next->data + indent_len,
2571 current->next->data + indent_len + break_pos + 1,
2572 next_line_len - break_pos - indent_len);
2573 null_at(&current->next->data,
2574 next_line_len - break_pos);
2575 current = current->next;
2576 }
2577 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002578 continue_loc:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002579 current = current->next;
2580 }
2581/* We are now done justifying the paragraph. There are cleanup things to
2582 * do, and we check for unjustify. */
2583
2584 /* totlines, totsize, and current_y have been maintained above. We
2585 * now set last_par_line to the new end of the paragraph, update
2586 * fileage, set current_x. Also, edit_refresh() needs the line
2587 * numbers to be right, so we renumber(). */
2588 last_par_line = current->prev;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002589 if (first_mod_line != NULL) {
2590 if (first_mod_line->prev == NULL)
2591 fileage = first_mod_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002592 renumber(first_mod_line);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002593 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002594
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002595 if (current_y > editwinrows - 1)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002596 edit_update(current, CENTER);
2597 else
2598 edit_refresh();
2599
Chris Allegretta9149e612000-11-27 00:23:41 +00002600 statusbar(_("Can now UnJustify!"));
Chris Allegretta07798352000-11-27 22:58:23 +00002601 /* Change the shortcut list to display the unjustify code */
2602 shortcut_init(1);
2603 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002604 reset_cursor();
2605
Chris Allegretta6df90f52002-07-19 01:08:59 +00002606 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002607 * keystroke and return. */
Chris Allegretta5f071802001-05-06 02:34:31 +00002608
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002609#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002610 /* If it was a mouse click, parse it with do_mouse() and it might
2611 * become the unjustify key. Else give it back to the input stream. */
2612 if ((i = wgetch(edit)) == KEY_MOUSE)
Chris Allegretta5f071802001-05-06 02:34:31 +00002613 do_mouse();
2614 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00002615 ungetch(i);
Chris Allegretta5f071802001-05-06 02:34:31 +00002616#endif
Chris Allegretta5f071802001-05-06 02:34:31 +00002617
Chris Allegretta6df90f52002-07-19 01:08:59 +00002618 if ((i = wgetch(edit)) != NANO_UNJUSTIFY_KEY) {
2619 ungetch(i);
2620 /* Did we back up anything at all? */
2621 if (cutbuffer != cutbuffer_save)
2622 free_filestruct(cutbuffer);
2623 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002624 } else {
Chris Allegretta9149e612000-11-27 00:23:41 +00002625 /* Else restore the justify we just did (ungrateful user!) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002626 current = current_save;
2627 current_x = current_x_save;
2628 current_y = current_y_save;
2629 edittop = edittop_save;
2630 editbot = editbot_save;
2631 if (first_mod_line != NULL) {
2632 filestruct *cutbottom = get_cutbottom();
Chris Allegrettad022eac2000-11-27 02:50:49 +00002633
Chris Allegretta6df90f52002-07-19 01:08:59 +00002634 /* Splice the cutbuffer back into the file. */
2635 cutbottom->next = last_par_line->next;
2636 cutbottom->next->prev = cutbottom;
2637 /* The line numbers after the end of the paragraph have
2638 * been changed, so we change them back. */
2639 renumber(cutbottom->next);
2640 if (first_mod_line->prev != NULL) {
2641 cutbuffer->prev = first_mod_line->prev;
2642 cutbuffer->prev->next = cutbuffer;
2643 } else
2644 fileage = cutbuffer;
2645 cutbuffer = NULL;
2646
2647 last_par_line->next = NULL;
2648 free_filestruct(first_mod_line);
2649
2650 /* Restore global variables from before justify */
2651 totsize = totsize_save;
2652 totlines = filebot->lineno;
2653#ifndef NANO_SMALL
2654 mark_beginbuf = mark_beginbuf_save;
2655 mark_beginx = mark_beginx_save;
2656#endif
2657 flags = flags_save;
2658 if (!ISSET(MODIFIED)) {
2659 titlebar(NULL);
2660 wrefresh(topwin);
2661 }
2662 }
2663 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002664 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002665 cutbuffer = cutbuffer_save;
2666 blank_statusbar_refresh();
2667 /* display shortcut list without UnCut */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002668 shortcut_init(0);
2669 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002670
Chris Allegretta6df90f52002-07-19 01:08:59 +00002671 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002672#endif
2673}
2674
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002675int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002676{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002677 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002678
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002679 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002680
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002681#ifdef ENABLE_MULTIBUFFER
2682 if (!close_open_file()) {
2683 display_main_list();
2684 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002685 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002686 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002687#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002688 finish(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00002689 }
2690
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002691 if (ISSET(TEMP_OPT)) {
2692 i = 1;
2693 } else {
2694 i = do_yesno(0, 0,
2695 _
2696 ("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2697 }
2698
2699#ifdef DEBUG
2700 dump_buffer(fileage);
2701#endif
2702
2703 if (i == 1) {
2704 if (do_writeout(filename, 1, 0) > 0) {
2705
2706#ifdef ENABLE_MULTIBUFFER
2707 if (!close_open_file()) {
2708 display_main_list();
2709 return 1;
2710 }
2711 else
2712#endif
2713 finish(0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002714 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002715 } else if (i == 0) {
2716
2717#ifdef ENABLE_MULTIBUFFER
2718 if (!close_open_file()) {
2719 display_main_list();
2720 return 1;
2721 }
2722 else
2723#endif
2724 finish(0);
2725 } else
2726 statusbar(_("Cancelled"));
2727
2728 display_main_list();
2729 return 1;
2730}
2731
2732void signal_init(void)
2733{
2734#ifdef _POSIX_VDISABLE
2735 struct termios term;
2736#endif
2737
2738 /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */
2739 memset(&act, 0, sizeof(struct sigaction));
2740 act.sa_handler = SIG_IGN;
2741 sigaction(SIGINT, &act, NULL);
2742
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002743 /* Trap SIGHUP and SIGTERM cuz we want to write the file out. */
2744 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002745 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002746 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002747
2748#ifndef NANO_SMALL
2749 act.sa_handler = handle_sigwinch;
2750 sigaction(SIGWINCH, &act, NULL);
2751#endif
2752
2753#ifdef _POSIX_VDISABLE
2754 tcgetattr(0, &term);
2755
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002756 /* Ignore ^S, much to Chris' chagrin */
Chris Allegrettae42df732002-10-15 00:27:55 +00002757 term.c_cc[VSTOP] = _POSIX_VDISABLE;
2758
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002759#ifdef VDSUSP
2760 term.c_cc[VDSUSP] = _POSIX_VDISABLE;
2761#endif /* VDSUSP */
2762
2763#endif /* _POSIX_VDISABLE */
2764
2765 if (!ISSET(SUSPEND)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002766 /* Insane! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002767#ifdef _POSIX_VDISABLE
2768 term.c_cc[VSUSP] = _POSIX_VDISABLE;
2769#else
2770 act.sa_handler = SIG_IGN;
2771 sigaction(SIGTSTP, &act, NULL);
2772#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002773 } else {
2774 /* If we don't do this, it seems other stuff interrupts the
2775 suspend handler! Try using nano with mutt without this
2776 line. */
2777 sigfillset(&act.sa_mask);
2778
2779 act.sa_handler = do_suspend;
2780 sigaction(SIGTSTP, &act, NULL);
2781
2782 act.sa_handler = do_cont;
2783 sigaction(SIGCONT, &act, NULL);
2784 }
2785
2786#ifdef _POSIX_VDISABLE
2787 tcsetattr(0, TCSANOW, &term);
2788#endif
2789}
2790
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002791/* Handler for SIGHUP and SIGTERM */
2792RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002793{
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002794 die(_("Received SIGHUP or SIGTERM"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002795}
2796
2797/* What do we do when we catch the suspend signal */
2798RETSIGTYPE do_suspend(int signal)
2799{
2800 endwin();
2801 printf("\n\n\n\n\nUse \"fg\" to return to nano\n");
2802 fflush(stdout);
2803
2804 /* Restore the terminal settings for the disabled keys */
2805 tcsetattr(0, TCSANOW, &oldterm);
2806
2807 /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002808 then we could be (and were) interrupted in the middle of the call.
2809 So we do it the mutt way instead */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002810 kill(0, SIGSTOP);
2811}
2812
2813/* Restore the suspend handler when we come back into the prog */
2814RETSIGTYPE do_cont(int signal)
2815{
2816 /* Now we just update the screen instead of having to reenable the
2817 SIGTSTP handler. */
2818
2819 doupdate();
2820 /* The Hurd seems to need this, otherwise a ^Y after a ^Z will
2821 start suspending again. */
2822 signal_init();
2823
2824#ifndef NANO_SMALL
2825 /* Perhaps the user resized the window while we slept. */
2826 handle_sigwinch(0);
2827#endif
2828}
2829
2830#ifndef NANO_SMALL
2831void handle_sigwinch(int s)
2832{
2833 const char *tty = ttyname(0);
2834 int fd;
2835 int result = 0;
2836 struct winsize win;
2837
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002838 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002839 return;
2840 fd = open(tty, O_RDWR);
2841 if (fd == -1)
2842 return;
2843 result = ioctl(fd, TIOCGWINSZ, &win);
2844 close(fd);
2845 if (result == -1)
2846 return;
2847
2848 /* Could check whether the COLS or LINES changed, and return
2849 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2850 * variables, and in some cases ncurses has already updated them.
2851 * But not in all cases, argh. */
2852 COLS = win.ws_col;
2853 LINES = win.ws_row;
2854 if ((editwinrows = LINES - 5 + no_help()) < MIN_EDITOR_ROWS)
2855 die_too_small();
2856
2857#ifndef DISABLE_WRAPJUSTIFY
2858 fill = wrap_at;
2859 if (fill <= 0)
2860 fill += COLS;
2861 if (fill < MIN_FILL_LENGTH)
2862 die_too_small();
2863#endif
2864
2865 hblank = nrealloc(hblank, COLS + 1);
2866 memset(hblank, ' ', COLS);
2867 hblank[COLS] = '\0';
2868
2869#ifdef HAVE_RESIZETERM
2870 resizeterm(LINES, COLS);
2871#ifdef HAVE_WRESIZE
2872 if (wresize(topwin, 2, COLS) == ERR)
2873 die(_("Cannot resize top win"));
2874 if (mvwin(topwin, 0, 0) == ERR)
2875 die(_("Cannot move top win"));
2876 if (wresize(edit, editwinrows, COLS) == ERR)
2877 die(_("Cannot resize edit win"));
2878 if (mvwin(edit, 2, 0) == ERR)
2879 die(_("Cannot move edit win"));
2880 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
2881 die(_("Cannot resize bottom win"));
2882 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
2883 die(_("Cannot move bottom win"));
2884#endif /* HAVE_WRESIZE */
2885#endif /* HAVE_RESIZETERM */
2886
2887 fix_editbot();
2888
2889 if (current_y > editwinrows - 1)
2890 edit_update(editbot, CENTER);
2891 erase();
2892
2893 /* Do these b/c width may have changed... */
2894 refresh();
2895 titlebar(NULL);
2896 edit_refresh();
2897 display_main_list();
2898 blank_statusbar();
2899 total_refresh();
2900
2901 /* Turn cursor back on for sure */
2902 curs_set(1);
2903
2904 /* Jump back to main loop */
2905 siglongjmp(jmpbuf, 1);
2906}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002907#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002908
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002909/* If the NumLock key has made the keypad go awry, print an error
2910 message; hopefully we can address it later. */
2911void print_numlock_warning(void)
2912{
2913 static int didmsg = 0;
2914 if (!didmsg) {
2915 statusbar(_
2916 ("NumLock glitch detected. Keypad will malfunction with NumLock off"));
2917 didmsg = 1;
2918 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002919}
2920
Chris Allegrettadab017e2002-04-23 10:56:06 +00002921#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002922void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002923{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002924 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002925
Chris Allegretta658399a2001-06-14 02:54:22 +00002926 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002927 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002928
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002929 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002930 case TOGGLE_PICOMODE_KEY:
Chris Allegretta07798352000-11-27 22:58:23 +00002931 shortcut_init(0);
Chris Allegrettac1049ac2001-08-17 00:03:46 +00002932 SET(CLEAR_BACKUPSTRING);
Chris Allegretta756f2202000-09-01 13:32:47 +00002933 display_main_list();
2934 break;
2935 case TOGGLE_SUSPEND_KEY:
2936 signal_init();
2937 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002938#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta756f2202000-09-01 13:32:47 +00002939 case TOGGLE_MOUSE_KEY:
2940 mouse_init();
2941 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002942#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002943 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00002944 wclear(bottomwin);
2945 wrefresh(bottomwin);
2946 window_init();
Chris Allegrettaaffeda82000-12-18 04:03:48 +00002947 fix_editbot();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002948 edit_refresh();
2949 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002950 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002951 case TOGGLE_DOS_KEY:
2952 UNSET(MAC_FILE);
2953 break;
2954 case TOGGLE_MAC_KEY:
2955 UNSET(DOS_FILE);
2956 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002957#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002958 case TOGGLE_SYNTAX_KEY:
2959 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002960 break;
2961#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002962 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002963
Chris Allegretta6df90f52002-07-19 01:08:59 +00002964 /* We are assuming here that shortcut_init() above didn't free and
2965 * reallocate the toggles. */
2966 enabled = ISSET(which->flag);
2967 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2968 enabled = !enabled;
2969 statusbar("%s %s", which->desc,
2970 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002971}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002972#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002973
Chris Allegretta1748cd12001-01-13 17:22:54 +00002974/* This function returns the correct keystroke, given the A,B,C or D
2975 input key. This is a common sequence of many terms which send
2976 Esc-O-[A-D] or Esc-[-[A-D]. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002977int abcd(int input)
Chris Allegretta1748cd12001-01-13 17:22:54 +00002978{
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002979 switch (input) {
2980 case 'A':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002981 case 'a':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002982 return KEY_UP;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002983 case 'B':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002984 case 'b':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002985 return KEY_DOWN;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002986 case 'C':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002987 case 'c':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002988 return KEY_RIGHT;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002989 case 'D':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002990 case 'd':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002991 return KEY_LEFT;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002992 default:
2993 return 0;
Chris Allegretta1748cd12001-01-13 17:22:54 +00002994 }
2995}
2996
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002997int main(int argc, char *argv[])
2998{
2999 int optchr;
3000 int kbinput; /* Input from keyboard */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003001 int startline = 0; /* Line to try and start at */
Chris Allegretta08020882001-01-29 23:37:54 +00003002 int keyhandled; /* Have we handled the keystroke yet? */
Chris Allegretta9caa1932002-02-15 20:08:05 +00003003 int modify_control_seq;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003004 const char *argv0;
3005 const shortcut *s;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003006#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003007 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003008#endif
Chris Allegretta0357c4d2001-09-19 02:59:25 +00003009
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003010#ifdef _POSIX_VDISABLE
3011 struct termios term;
3012#endif
3013
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003014#ifdef HAVE_GETOPT_LONG
3015 int option_index = 0;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003016 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003017 {"help", 0, 0, 'h'},
3018#ifdef ENABLE_MULTIBUFFER
3019 {"multibuffer", 0, 0, 'F'},
3020#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003021#ifdef ENABLE_NANORC
3022 {"ignorercfiles", 0, 0, 'I'},
3023#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003024 {"keypad", 0, 0, 'K'},
3025#ifndef DISABLE_JUSTIFY
3026 {"quotestr", 1, 0, 'Q'},
3027#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003028#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003029 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003030#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003031 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003032 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003033#ifdef ENABLE_COLOR
3034 {"syntax", 1, 0, 'Y'},
3035#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003036 {"const", 0, 0, 'c'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003037 {"nofollow", 0, 0, 'l'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003038#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003039 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003040#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003041#ifndef DISABLE_OPERATINGDIR
3042 {"operatingdir", 1, 0, 'o'},
3043#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003044 {"pico", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003045#ifndef DISABLE_WRAPJUSTIFY
3046 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003047#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003048#ifndef DISABLE_SPELLER
3049 {"speller", 1, 0, 's'},
3050#endif
3051 {"tempfile", 0, 0, 't'},
3052 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003053#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003054 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003055#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003056 {"nohelp", 0, 0, 'x'},
3057 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003058#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003059 {"backup", 0, 0, 'B'},
3060 {"dos", 0, 0, 'D'},
3061 {"mac", 0, 0, 'M'},
3062 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003063 {"smooth", 0, 0, 'S'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003064 {"autoindent", 0, 0, 'i'},
3065 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003066#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003067 {0, 0, 0, 0}
3068 };
3069#endif
3070
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003071#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003072 setlocale(LC_ALL, "");
3073 bindtextdomain(PACKAGE, LOCALEDIR);
3074 textdomain(PACKAGE);
3075#endif
3076
Chris Allegretta8d8e0122001-04-18 04:28:54 +00003077#ifdef ENABLE_NANORC
Chris Allegretta1c5c3382002-07-23 00:33:07 +00003078 {
3079 /* scan through the options and handle -I/--ignorercfiles
3080 first, so that it's handled before we call do_rcfile() and
3081 read the other options; don't use getopt()/getopt_long()
3082 here, because there's no way to reset it properly
3083 afterward */
3084 int i;
3085 for (i = 1; i < argc; i++) {
3086 if (!strcmp(argv[i], "--"))
3087 break;
3088 else if (!strcmp(argv[i], "-I"))
3089 SET(NO_RCFILE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003090#ifdef HAVE_GETOPT_LONG
Chris Allegretta1c5c3382002-07-23 00:33:07 +00003091 else if (!strcmp(argv[i], "--ignorercfiles"))
3092 SET(NO_RCFILE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00003093#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003094 }
3095 }
Chris Allegretta1c5c3382002-07-23 00:33:07 +00003096 if (!ISSET(NO_RCFILE))
3097 do_rcfile();
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003098#else
3099#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
3100 /* if we don't have rcfile support, we're root, and
3101 --disable-wrapping-as-root is used, turn wrapping off */
3102 if (geteuid() == 0)
3103 SET(NO_WRAP);
3104#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003105#endif /* ENABLE_NANORC */
3106
3107#ifdef HAVE_GETOPT_LONG
3108 while ((optchr = getopt_long(argc, argv, "h?BDFIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz",
3109 long_options, &option_index)) != EOF) {
3110#else
3111 while ((optchr =
3112 getopt(argc, argv, "h?BDFIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz")) != EOF) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003113#endif
3114
3115 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003116
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003117 case 'h':
3118 case '?':
3119 usage();
3120 exit(0);
3121 case 'a':
3122 case 'b':
3123 case 'e':
3124 case 'f':
3125 case 'g':
3126 case 'j':
3127 /* Pico compatibility flags */
3128 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003129#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003130 case 'B':
3131 SET(BACKUP_FILE);
3132 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003133 case 'D':
3134 SET(DOS_FILE);
3135 break;
3136#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003137#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003138 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003139 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003140 break;
3141#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003142#ifdef ENABLE_NANORC
Chris Allegretta6df90f52002-07-19 01:08:59 +00003143 case 'I':
3144 break;
3145#endif
Chris Allegretta48bd3782002-01-03 21:26:34 +00003146 case 'K':
3147 SET(ALT_KEYPAD);
3148 break;
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003149#ifndef NANO_SMALL
3150 case 'M':
3151 SET(MAC_FILE);
3152 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003153 case 'N':
3154 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003155 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003156#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003157#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003158 case 'Q':
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003159 quotestr = optarg;
3160 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003161#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003162#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003163 case 'R':
3164 SET(USE_REGEXP);
3165 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003166#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003167#ifndef NANO_SMALL
3168 case 'S':
3169 SET(SMOOTHSCROLL);
3170 break;
3171#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003172 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003173 {
3174 int i;
3175 char *first_error;
3176
3177 /* Using strtol instead of atoi lets us accept 0 while
3178 * checking other errors. */
3179 i = (int)strtol(optarg, &first_error, 10);
3180 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0') {
3181 usage();
3182 exit(1);
3183 } else
3184 tabsize = i;
3185 if (tabsize <= 0) {
3186 fprintf(stderr, _("Tab size is too small for nano...\n"));
3187 exit(1);
3188 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003189 }
3190 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003191 case 'V':
3192 version();
3193 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003194#ifdef ENABLE_COLOR
3195 case 'Y':
3196 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3197 break;
3198#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003199 case 'c':
3200 SET(CONSTUPDATE);
3201 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003202#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003203 case 'i':
3204 SET(AUTOINDENT);
3205 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003206 case 'k':
3207 SET(CUT_TO_END);
3208 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003209#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003210 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003211 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003212 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003213#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003214 case 'm':
3215 SET(USE_MOUSE);
3216 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003217#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003218#ifndef DISABLE_OPERATINGDIR
3219 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003220 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003221 break;
3222#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003223 case 'p':
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +00003224 SET(PICO_MODE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003225 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003226#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003227 case 'r':
3228 {
3229 int i;
3230 char *first_error;
3231
3232 /* Using strtol instead of atoi lets us accept 0 while
3233 * checking other errors. */
3234 i = (int)strtol(optarg, &first_error, 10);
3235 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0') {
3236 usage();
3237 exit(1);
3238 } else
3239 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003240 }
3241 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003242#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003243#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003244 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003245 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003246 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003247#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003248 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003249 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003250 break;
3251 case 'v':
3252 SET(VIEW_MODE);
3253 break;
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00003254#ifdef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003255 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003256 SET(NO_WRAP);
3257 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003258#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003259 case 'x':
3260 SET(NO_HELP);
3261 break;
3262 case 'z':
3263 SET(SUSPEND);
3264 break;
3265 default:
3266 usage();
Chris Allegretta4da1fc62000-06-21 03:00:43 +00003267 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003268 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003269 }
3270
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003271#ifndef DISABLE_OPERATINGDIR
3272 /* Set up the operating directory. This entails chdir()ing there, so
3273 that file reads and writes will be based there. */
3274 init_operating_dir();
3275#endif
3276
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003277 /* Clear the filename we'll be using */
3278 filename = charalloc(1);
3279 filename[0] = '\0';
3280
3281 /* See if we were invoked with the name "pico" */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003282 argv0 = strrchr(argv[0], '/');
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003283 if ((argv0 != NULL && strstr(argv0, "pico") != NULL)
3284 || (argv0 == NULL && strstr(argv[0], "pico") != NULL))
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +00003285 SET(PICO_MODE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003286
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003287 /* See if there's a non-option in argv (first non-option is the
3288 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003289 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003290 /* Look for the +line flag... */
3291 if (argv[optind][0] == '+') {
3292 startline = atoi(&argv[optind][1]);
3293 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003294 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003295 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003296 } else
3297 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003298 }
3299
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003300 /* First back up the old settings so they can be restored, duh */
3301 tcgetattr(0, &oldterm);
3302
3303#ifdef _POSIX_VDISABLE
3304 term = oldterm;
3305 term.c_cc[VINTR] = _POSIX_VDISABLE;
3306 term.c_cc[VQUIT] = _POSIX_VDISABLE;
3307 term.c_lflag &= ~IEXTEN;
3308 tcsetattr(0, TCSANOW, &term);
3309#endif
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003310
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003311 /* now ncurses init stuff... */
3312 initscr();
3313 savetty();
3314 nonl();
3315 cbreak();
3316 noecho();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003317
3318 /* Set up some global variables */
Chris Allegretta56214c62001-09-27 02:46:53 +00003319 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003320 shortcut_init(0);
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003321 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003322
3323#ifdef DEBUG
3324 fprintf(stderr, _("Main: set up windows\n"));
3325#endif
3326
Chris Allegretta2a42af12000-09-12 23:02:49 +00003327 window_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003328#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta756f2202000-09-01 13:32:47 +00003329 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003330#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003331
Chris Allegretta48bd3782002-01-03 21:26:34 +00003332 if (!ISSET(ALT_KEYPAD)) {
3333 keypad(edit, TRUE);
3334 keypad(bottomwin, TRUE);
3335 }
3336
Chris Allegretta08893e02001-11-29 02:42:27 +00003337#ifdef ENABLE_COLOR
3338 do_colorinit();
Chris Allegretta08893e02001-11-29 02:42:27 +00003339#endif /* ENABLE_COLOR */
3340
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003341#ifdef DEBUG
3342 fprintf(stderr, _("Main: bottom win\n"));
3343#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003344 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003345 display_main_list();
3346
3347#ifdef DEBUG
3348 fprintf(stderr, _("Main: open file\n"));
3349#endif
3350
Chris Allegretta31c76662000-11-21 06:20:20 +00003351 /* Now we check to see if argv[optind] is non-null to determine if
3352 we're dealing with a new file or not, not argc == 1... */
3353 if (argv[optind] == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003354 new_file();
3355 else
3356 open_file(filename, 0, 0);
3357
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003358 titlebar(NULL);
3359
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003360 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003361 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003362 else
Chris Allegretta234a34d2000-07-29 04:33:38 +00003363 edit_update(fileage, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003364
Chris Allegretta08020882001-01-29 23:37:54 +00003365 /* return here after a sigwinch */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003366 sigsetjmp(jmpbuf, 1);
Chris Allegretta08020882001-01-29 23:37:54 +00003367
3368 /* Fix clobber-age */
3369 kbinput = 0;
3370 keyhandled = 0;
3371 modify_control_seq = 0;
3372
Robert Siemborski6967eec2000-07-08 14:23:32 +00003373 edit_refresh();
3374 reset_cursor();
3375
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003376 while (1) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003377
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003378#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003379 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003380#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003381
Chris Allegretta9239d742000-09-06 15:19:18 +00003382#ifndef _POSIX_VDISABLE
3383 /* We're going to have to do it the old way, i.e. on cygwin */
3384 raw();
3385#endif
3386
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003387 kbinput = wgetch(edit);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003388#ifdef DEBUG
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003389 fprintf(stderr, _("AHA! %c (%d)\n"), kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003390#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003391 if (kbinput == 27) { /* Grab Alt-key stuff first */
3392 switch (kbinput = wgetch(edit)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003393 /* Alt-O, suddenly very important ;) */
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003394 case 'O':
Chris Allegretta16e41682000-09-11 22:33:54 +00003395 kbinput = wgetch(edit);
Chris Allegretta316e4d92001-04-28 16:31:19 +00003396 if ((kbinput <= 'D' && kbinput >= 'A') ||
3397 (kbinput <= 'd' && kbinput >= 'a'))
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003398 kbinput = abcd(kbinput);
Chris Allegretta201d9bf2001-01-14 03:17:53 +00003399 else if (kbinput <= 'z' && kbinput >= 'j')
3400 print_numlock_warning();
3401 else if (kbinput <= 'S' && kbinput >= 'P')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003402 kbinput = KEY_F(kbinput - 79);
Chris Allegretta16e41682000-09-11 22:33:54 +00003403#ifdef DEBUG
3404 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003405 fprintf(stderr, _("I got Alt-O-%c! (%d)\n"),
3406 kbinput, kbinput);
3407 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003408 }
3409#endif
3410 break;
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003411 case 27:
3412 /* If we get Alt-Alt, the next keystroke should be the same as a
3413 control sequence */
3414 modify_control_seq = 1;
3415 keyhandled = 1;
3416 break;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003417 case '[':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003418 switch (kbinput = wgetch(edit)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003419 case '1': /* Alt-[-1-[0-5,7-9] = F1-F8 in X at least */
Chris Allegretta16e41682000-09-11 22:33:54 +00003420 kbinput = wgetch(edit);
3421 if (kbinput >= '1' && kbinput <= '5') {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003422 kbinput = KEY_F(kbinput - 48);
3423 wgetch(edit);
3424 } else if (kbinput >= '7' && kbinput <= '9') {
3425 kbinput = KEY_F(kbinput - 49);
3426 wgetch(edit);
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003427 } else if (kbinput == '~')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003428 kbinput = KEY_HOME;
Chris Allegretta16e41682000-09-11 22:33:54 +00003429#ifdef DEBUG
3430 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003431 fprintf(stderr, _("I got Alt-[-1-%c! (%d)\n"),
3432 kbinput, kbinput);
3433 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003434 }
3435#endif
Chris Allegretta16e41682000-09-11 22:33:54 +00003436 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003437 case '2': /* Alt-[-2-[0,1,3,4] = F9-F12 in many terms */
Chris Allegretta16e41682000-09-11 22:33:54 +00003438 kbinput = wgetch(edit);
Chris Allegretta16e41682000-09-11 22:33:54 +00003439 switch (kbinput) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003440 case '0':
3441 kbinput = KEY_F(9);
3442 wgetch(edit);
3443 break;
3444 case '1':
3445 kbinput = KEY_F(10);
3446 wgetch(edit);
3447 break;
3448 case '3':
3449 kbinput = KEY_F(11);
3450 wgetch(edit);
3451 break;
3452 case '4':
3453 kbinput = KEY_F(12);
3454 wgetch(edit);
3455 break;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003456 case '~':
3457 goto do_insertkey;
Chris Allegretta16e41682000-09-11 22:33:54 +00003458#ifdef DEBUG
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003459 default:
3460 fprintf(stderr, _("I got Alt-[-2-%c! (%d)\n"),
3461 kbinput, kbinput);
3462 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003463#endif
Chris Allegretta16e41682000-09-11 22:33:54 +00003464 }
3465 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003466 case '3': /* Alt-[-3 = Delete? */
Chris Allegretta16e41682000-09-11 22:33:54 +00003467 kbinput = NANO_DELETE_KEY;
3468 wgetch(edit);
3469 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003470 case '4': /* Alt-[-4 = End? */
Chris Allegretta16e41682000-09-11 22:33:54 +00003471 kbinput = NANO_END_KEY;
3472 wgetch(edit);
3473 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003474 case '5': /* Alt-[-5 = Page Up */
Chris Allegretta16e41682000-09-11 22:33:54 +00003475 kbinput = KEY_PPAGE;
3476 wgetch(edit);
3477 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003478 case 'V': /* Alt-[-V = Page Up in Hurd Console */
Chris Allegretta7bf72742001-10-28 04:29:55 +00003479 case 'I': /* Alt-[-I = Page Up - FreeBSD Console */
3480 kbinput = KEY_PPAGE;
3481 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003482 case '6': /* Alt-[-6 = Page Down */
Chris Allegretta16e41682000-09-11 22:33:54 +00003483 kbinput = KEY_NPAGE;
3484 wgetch(edit);
3485 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003486 case 'U': /* Alt-[-U = Page Down in Hurd Console */
Chris Allegretta7bf72742001-10-28 04:29:55 +00003487 case 'G': /* Alt-[-G = Page Down - FreeBSD Console */
3488 kbinput = KEY_NPAGE;
3489 break;
Chris Allegrettab26ecb52001-07-04 16:27:05 +00003490 case '7':
3491 kbinput = KEY_HOME;
3492 wgetch(edit);
3493 break;
3494 case '8':
3495 kbinput = KEY_END;
3496 wgetch(edit);
3497 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003498 case '9': /* Alt-[-9 = Delete in Hurd Console */
3499 kbinput = KEY_DC;
3500 break;
Chris Allegretta32da4562002-01-02 15:12:21 +00003501 case '@': /* Alt-[-@ = Insert in Hurd Console */
3502 case 'L': /* Alt-[-L = Insert - FreeBSD Console */
3503 goto do_insertkey;
3504 case '[': /* Alt-[-[-[A-E], F1-F5 in Linux console */
Chris Allegretta16e41682000-09-11 22:33:54 +00003505 kbinput = wgetch(edit);
Chris Allegrettab26ecb52001-07-04 16:27:05 +00003506 if (kbinput >= 'A' && kbinput <= 'E')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003507 kbinput = KEY_F(kbinput - 64);
Chris Allegretta16e41682000-09-11 22:33:54 +00003508 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003509 case 'A':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003510 case 'B':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003511 case 'C':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003512 case 'D':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003513 case 'a':
3514 case 'b':
3515 case 'c':
3516 case 'd':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003517 kbinput = abcd(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003518 break;
3519 case 'H':
3520 kbinput = KEY_HOME;
3521 break;
3522 case 'F':
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003523 case 'Y': /* End Key in Hurd Console */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003524 kbinput = KEY_END;
3525 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003526 default:
3527#ifdef DEBUG
3528 fprintf(stderr, _("I got Alt-[-%c! (%d)\n"),
3529 kbinput, kbinput);
3530#endif
3531 break;
3532 }
3533 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003534
Chris Allegretta355fbe52001-07-14 19:32:47 +00003535#ifdef ENABLE_MULTIBUFFER
Chris Allegretta819e3db2001-07-11 02:37:19 +00003536 case NANO_OPENPREV_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003537 case NANO_OPENPREV_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003538 open_prevfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003539 keyhandled = 1;
3540 break;
3541 case NANO_OPENNEXT_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003542 case NANO_OPENNEXT_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003543 open_nextfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003544 keyhandled = 1;
3545 break;
Chris Allegretta9cf9e062001-07-11 12:06:13 +00003546#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003547 default:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003548 /* Check for the altkey defs.... */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003549 for (s = main_list; s != NULL; s = s->next)
3550 if (kbinput == s->altval ||
Chris Allegretta6232d662002-05-12 19:52:15 +00003551 kbinput == s->altval - 32) {
3552 if (ISSET(VIEW_MODE) && !s->viewok)
3553 print_view_warning();
3554 else
3555 s->func();
3556 keyhandled = 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003557 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003558 }
Chris Allegretta756f2202000-09-01 13:32:47 +00003559#ifndef NANO_SMALL
3560 /* And for toggle switches */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003561 for (t = toggles; t != NULL && !keyhandled; t = t->next)
3562 if (kbinput == t->val ||
3563 (t->val > 'a' &&
3564 kbinput == t->val - 32)) {
3565 do_toggle(t);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003566 keyhandled = 1;
3567 break;
Chris Allegretta756f2202000-09-01 13:32:47 +00003568 }
3569#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003570#ifdef DEBUG
3571 fprintf(stderr, _("I got Alt-%c! (%d)\n"), kbinput,
3572 kbinput);
3573#endif
3574 break;
3575 }
3576 }
Chris Allegrettacf287c82002-07-20 13:57:41 +00003577 /* If modify_control_seq is set, we received an Alt-Alt
3578 sequence before this, so we make this key a control sequence
3579 by subtracting 32, 64, or 96, depending on its value. */
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003580 if (!keyhandled && modify_control_seq) {
Chris Allegrettacf287c82002-07-20 13:57:41 +00003581 if (kbinput == ' ')
3582 kbinput -= 32;
3583 else if (kbinput >= 'A' && kbinput < 'a')
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003584 kbinput -= 64;
3585 else if (kbinput >= 'a' && kbinput <= 'z')
3586 kbinput -= 96;
3587
3588 modify_control_seq = 0;
3589 }
3590
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003591 /* Look through the main shortcut list to see if we've hit a
3592 shortcut key */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003593
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003594#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003595 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
Chris Allegrettaf5de33a2002-02-27 04:14:16 +00003596#else
3597 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
3598#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003599 if (kbinput == s->val ||
3600 (s->misc1 && kbinput == s->misc1) ||
3601 (s->misc2 && kbinput == s->misc2)) {
3602 if (ISSET(VIEW_MODE) && !s->viewok)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003603 print_view_warning();
3604 else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003605 s->func();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003606 keyhandled = 1;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003607 /* rarely, the value of s can change after s->func(),
3608 leading to problems; get around this by breaking out
3609 explicitly once we successfully handle a shortcut */
3610 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003611 }
3612 }
Chris Allegrettae42df732002-10-15 00:27:55 +00003613
3614#ifdef _POSIX_VDISABLE
3615 /* Don't even think about changing this string */
3616 if (kbinput == 19)
3617 statusbar(_("XOFF ignored, mumble mumble."));
3618#endif
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003619 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3620 Control-S and Control-Q */
Chris Allegretta9239d742000-09-06 15:19:18 +00003621 if (kbinput == 17 || kbinput == 19)
3622 keyhandled = 1;
3623
Chris Allegretta9caa1932002-02-15 20:08:05 +00003624 /* Catch ^Z by hand when triggered also
3625 407 == ^Z in Linux console when keypad() is used? */
3626 if (kbinput == 26 || kbinput == 407) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003627 if (ISSET(SUSPEND))
3628 do_suspend(0);
3629 keyhandled = 1;
3630 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003631
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003632 /* Hack, make insert key do something useful, like insert file */
3633 if (kbinput == KEY_IC) {
3634 do_insertkey:
3635
3636#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +00003637 /* do_insertfile_void() contains the logic needed to
3638 handle view mode with the view mode/multibuffer
3639 exception, so use it here */
3640 do_insertfile_void();
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003641#else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003642 if (!ISSET(VIEW_MODE))
3643 do_insertfile_void();
3644 else
3645 print_view_warning();
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003646#endif
3647
Chris Allegretta1c27d3e2001-10-02 02:56:45 +00003648 keyhandled = 1;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003649 }
3650
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003651 /* Last gasp, stuff that's not in the main lists */
3652 if (!keyhandled)
3653 switch (kbinput) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003654#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003655 case KEY_MOUSE:
3656 do_mouse();
3657 break;
3658#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003659
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003660 case 0: /* Erg */
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003661 case -1: /* Stuff that we don't want to do squat */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003662 case 410: /* Must ignore this, it gets sent when we resize */
Chris Allegrettab3655b42001-10-22 03:15:31 +00003663 case 29: /* Ctrl-] */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003664#ifdef PDCURSES
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003665 case 541: /* ???? */
3666 case 542: /* Control and alt in Windows *shrug* */
Chris Allegretta72623582000-11-29 23:43:28 +00003667 case 543: /* Right ctrl key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003668 case 544:
Chris Allegretta72623582000-11-29 23:43:28 +00003669 case 545: /* Right alt key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003670#endif
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003671
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003672 break;
3673 default:
3674#ifdef DEBUG
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003675 fprintf(stderr, _("I got %c (%d)!\n"), kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003676#endif
3677 /* We no longer stop unhandled sequences so that people with
3678 odd character sets can type... */
3679
3680 if (ISSET(VIEW_MODE)) {
3681 print_view_warning();
3682 break;
3683 }
3684 do_char(kbinput);
3685 }
Chris Allegretta7fdbd052001-10-02 00:55:38 +00003686 if (ISSET(DISABLE_CURPOS))
3687 UNSET(DISABLE_CURPOS);
3688 else if (ISSET(CONSTUPDATE))
Chris Allegretta2084acc2001-11-29 03:43:08 +00003689 do_cursorpos(1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003690
3691 reset_cursor();
3692 wrefresh(edit);
3693 keyhandled = 0;
3694 }
3695
3696 getchar();
3697 finish(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003698}