blob: 890d5cdb1afde05412c4715179288dcc9e4c62c2 [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 */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000114 if (open_files) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000115 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000116
117 tmp = open_files;
118
119 while (open_files->prev)
120 open_files = open_files->prev;
121
122 while (open_files->next) {
123
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
231 /* Oops, I guess we need this again.
232 Moved here so the keypad still works after a Meta-X, for example */
233 keypad(edit, TRUE);
234 keypad(bottomwin, TRUE);
235#endif
236}
237
238void mouse_init(void)
239{
240#ifndef DISABLE_MOUSE
241#ifdef NCURSES_MOUSE_VERSION
242 if (ISSET(USE_MOUSE)) {
243 keypad_on(edit, 1);
244 keypad_on(bottomwin, 1);
245
246 mousemask(BUTTON1_RELEASED, NULL);
247 mouseinterval(50);
248 } else
249 mousemask(0, NULL);
250#endif
251#endif
252}
253
254#ifndef DISABLE_HELP
255/* This function allocates help_text, and stores the help string in it.
256 * help_text should be NULL initially. */
257void help_init(void)
258{
259 size_t allocsize = 1; /* space needed for help_text */
260 char *ptr = NULL;
261#ifndef NANO_SMALL
262 const toggle *t;
263#endif
264 const shortcut *s;
265
266 /* First set up the initial help text for the current function */
267 if (currshortcut == whereis_list || currshortcut == replace_list
268 || currshortcut == replace_list_2)
269 ptr = _("Search Command Help Text\n\n "
270 "Enter the words or characters you would like to search "
271 "for, then hit enter. If there is a match for the text you "
272 "entered, the screen will be updated to the location of the "
273 "nearest match for the search string.\n\n "
274 "If using Pico Mode via the -p or --pico flags, the "
275 "Meta-P toggle, or a nanorc file, the previous search "
276 "string will be shown in brackets after the Search: prompt. "
277 "Hitting Enter without entering any text will perform the "
278 "previous search. Otherwise, the previous string will be "
279 "placed before the cursor, and can be edited or deleted "
280 "before hitting enter.\n\n The following function keys are "
281 "available in Search mode:\n\n");
282 else if (currshortcut == goto_list)
283 ptr = _("Go To Line Help Text\n\n "
284 "Enter the line number that you wish to go to and hit "
285 "Enter. If there are fewer lines of text than the "
286 "number you entered, you will be brought to the last line "
287 "of the file.\n\n The following function keys are "
288 "available in Go To Line mode:\n\n");
289 else if (currshortcut == insertfile_list)
290 ptr = _("Insert File Help Text\n\n "
291 "Type in the name of a file to be inserted into the current "
292 "file buffer at the current cursor location.\n\n "
293 "If you have compiled nano with multiple file buffer "
294 "support, and enable multiple buffers with the -F "
295 "or --multibuffer command line flags, the Meta-F toggle, or "
296 "a nanorc file, inserting a file will cause it to be "
297 "loaded into a separate buffer (use Meta-< and > to switch "
298 "between file buffers).\n\n If you need another blank "
299 "buffer, do not enter any filename, or type in a "
300 "nonexistent filename at the prompt and press "
301 "Enter.\n\n The following function keys are "
302 "available in Insert File mode:\n\n");
303 else if (currshortcut == writefile_list)
304 ptr = _("Write File Help Text\n\n "
305 "Type the name that you wish to save the current file "
306 "as and hit Enter to save the file.\n\n If you have "
307 "selected text with Ctrl-^, you will be prompted to "
308 "save only the selected portion to a separate file. To "
309 "reduce the chance of overwriting the current file with "
310 "just a portion of it, the current filename is not the "
311 "default in this mode.\n\n The following function keys "
312 "are available in Write File mode:\n\n");
313#ifndef DISABLE_BROWSER
314 else if (currshortcut == browser_list)
315 ptr = _("File Browser Help Text\n\n "
316 "The file browser is used to visually browse the "
317 "directory structure to select a file for reading "
318 "or writing. You may use the arrow keys or Page Up/"
319 "Down to browse through the files, and S or Enter to "
320 "choose the selected file or enter the selected "
321 "directory. To move up one level, select the directory "
322 "called \"..\" at the top of the file list.\n\n The "
323 "following function keys are available in the file "
324 "browser:\n\n");
325 else if (currshortcut == gotodir_list)
326 ptr = _("Browser Go To Directory Help Text\n\n "
327 "Enter the name of the directory you would like to "
328 "browse to.\n\n If tab completion has not been disabled, "
329 "you can use the TAB key to (attempt to) automatically "
330 "complete the directory name.\n\n The following function "
331 "keys are available in Browser Go To Directory mode:\n\n");
332#endif
333 else if (currshortcut == spell_list)
334 ptr = _("Spell Check Help Text\n\n "
335 "The spell checker checks the spelling of all text "
336 "in the current file. When an unknown word is "
337 "encountered, it is highlighted and a replacement can "
338 "be edited. It will then prompt to replace every "
339 "instance of the given misspelled word in the "
340 "current file.\n\n The following other functions are "
341 "available in Spell Check mode:\n\n");
342#ifndef NANO_SMALL
343 else if (currshortcut == extcmd_list)
344 ptr = _("External Command Help Text\n\n "
345 "This menu allows you to insert the output of a command "
346 "run by the shell into the current buffer (or a new "
347 "buffer in multibuffer mode).\n\n The following keys are "
348 "available in this mode:\n\n");
349#endif
350 else /* Default to the main help list */
351 ptr = _(" nano help text\n\n "
352 "The nano editor is designed to emulate the functionality and "
353 "ease-of-use of the UW Pico text editor. There are four main "
354 "sections of the editor: The top line shows the program "
355 "version, the current filename being edited, and whether "
356 "or not the file has been modified. Next is the main editor "
357 "window showing the file being edited. The status line is "
358 "the third line from the bottom and shows important messages. "
359 "The bottom two lines show the most commonly used shortcuts "
360 "in the editor.\n\n "
361 "The notation for shortcuts is as follows: Control-key "
362 "sequences are notated with a caret (^) symbol and are entered "
363 "with the Control (Ctrl) key. Escape-key sequences are notated "
364 "with the Meta (M) symbol and can be entered using either the "
365 "Esc, Alt or Meta key depending on your keyboard setup. The "
366 "following keystrokes are available in the main editor window. "
367 "Alternative keys are shown in parentheses:\n\n");
368
369 allocsize += strlen(ptr);
370
371 /* The space needed for the shortcut lists, at most COLS characters,
372 * plus '\n'. */
373 allocsize += (COLS + 1) * length_of_list(currshortcut);
374
375#ifndef NANO_SMALL
376 /* If we're on the main list, we also count the toggle help text.
377 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
378 * COLS - 24 characters, plus '\n'.*/
379 if (currshortcut == main_list)
380 for (t = toggles; t != NULL; t = t->next)
381 allocsize += COLS - 17;
382#endif /* !NANO_SMALL */
383
384 /* help_text has been freed and set to NULL unless the user resized
385 * while in the help screen. */
386 free(help_text);
387
388 /* Allocate space for the help text */
389 help_text = charalloc(allocsize);
390
391 /* Now add the text we want */
392 strcpy(help_text, ptr);
393 ptr = help_text + strlen(help_text);
394
395 /* Now add our shortcut info */
396 for (s = currshortcut; s != NULL; s = s->next) {
397 /* true if the character in s->altval is shown in first column */
398 int meta_shortcut = 0;
399
400 if (s->val > 0 && s->val < 32)
401 ptr += sprintf(ptr, "^%c", s->val + 64);
402#ifndef NANO_SMALL
403 else if (s->val == NANO_CONTROL_SPACE)
404 ptr += sprintf(ptr, "^%.6s", _("Space"));
405 else if (s->altval == NANO_ALT_SPACE) {
406 meta_shortcut = 1;
407 ptr += sprintf(ptr, "M-%.5s", _("Space"));
408 }
409#endif
410 else if (s->altval > 0) {
411 meta_shortcut = 1;
412 ptr += sprintf(ptr, "M-%c", s->altval -
413 (('A' <= s->altval && s->altval <= 'Z') ||
414 'a' <= s->altval ? 32 : 0));
415 }
416 /* Hack */
417 else if (s->val >= 'a') {
418 meta_shortcut = 1;
419 ptr += sprintf(ptr, "M-%c", s->val - 32);
420 }
421
422 *(ptr++) = '\t';
423
424 if (s->misc1 > KEY_F0 && s->misc1 <= KEY_F(64))
425 ptr += sprintf(ptr, "(F%d)", s->misc1 - KEY_F0);
426
427 *(ptr++) = '\t';
428
429 if (!meta_shortcut && s->altval > 0)
430 ptr += sprintf(ptr, "(M-%c)", s->altval -
431 (('A' <= s->altval && s->altval <= 'Z') || 'a' <= s->altval
432 ? 32 : 0));
433
434 *(ptr++) = '\t';
435
436 assert(s->help != NULL);
437 ptr += sprintf(ptr, "%.*s\n", COLS - 24, s->help);
438 }
439
440#ifndef NANO_SMALL
441 /* And the toggles... */
442 if (currshortcut == main_list)
443 for (t = toggles; t != NULL; t = t->next) {
444 ptr += sprintf(ptr, "M-%c\t\t\t", t->val - 32);
445 assert(t->desc != NULL);
446 ptr += sprintf(ptr, _("%.*s enable/disable\n"), COLS - 24, t->desc);
447 }
448#endif /* !NANO_SMALL */
449
450 /* If all went well, we didn't overwrite the allocated space for
451 help_text. */
452 assert(strlen(help_text) < allocsize);
453}
454#endif
455
456/* Create a new filestruct node. Note that we specifically do not set
457 * prevnode->next equal to the new line. */
458filestruct *make_new_node(filestruct *prevnode)
459{
460 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
461
462 newnode->data = NULL;
463 newnode->prev = prevnode;
464 newnode->next = NULL;
465 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
466
467 return newnode;
468}
469
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000470/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000471filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000472{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000473 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000474
Chris Allegretta6df90f52002-07-19 01:08:59 +0000475 assert(src != NULL);
476
Chris Allegretta88b09152001-05-17 11:35:43 +0000477 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000478 dst->next = src->next;
479 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000480 strcpy(dst->data, src->data);
481 dst->lineno = src->lineno;
482
483 return dst;
484}
485
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000486/* Splice a node into an existing filestruct. */
487void splice_node(filestruct *begin, filestruct *newnode, filestruct *end)
488{
489 if (newnode != NULL) {
490 newnode->next = end;
491 newnode->prev = begin;
492 }
493 if (begin != NULL)
494 begin->next = newnode;
495 if (end != NULL)
496 end->prev = newnode;
497}
498
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000499/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000500void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000501{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000502 assert(fileptr != NULL);
503
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000504 if (fileptr->prev != NULL)
505 fileptr->prev->next = fileptr->next;
506
507 if (fileptr->next != NULL)
508 fileptr->next->prev = fileptr->prev;
509}
510
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000511/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000512void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000513{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000514 if (fileptr != NULL) {
515 if (fileptr->data != NULL)
516 free(fileptr->data);
517 free(fileptr);
518 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000519}
520
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000521/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000522filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000523{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000524 filestruct *head; /* copy of src, top of the copied list */
525 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000526
Chris Allegretta6df90f52002-07-19 01:08:59 +0000527 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000528
Chris Allegretta6df90f52002-07-19 01:08:59 +0000529 prev = copy_node(src);
530 prev->prev = NULL;
531 head = prev;
532 src = src->next;
533 while (src != NULL) {
534 prev->next = copy_node(src);
535 prev->next->prev = prev;
536 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000537
Chris Allegretta6df90f52002-07-19 01:08:59 +0000538 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000539 }
540
Chris Allegretta6df90f52002-07-19 01:08:59 +0000541 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000542 return head;
543}
544
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000545/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000546void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000547{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000548 if (src != NULL) {
549 while (src->next != NULL) {
550 src = src->next;
551 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000552#ifdef DEBUG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000553 fprintf(stderr, _("delete_node(): free'd a node, YAY!\n"));
554#endif
555 }
556 delete_node(src);
557#ifdef DEBUG
558 fprintf(stderr, _("delete_node(): free'd last node.\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000559#endif
560 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000561}
562
Chris Allegretta6df90f52002-07-19 01:08:59 +0000563void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000564{
565 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000566 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000567
Chris Allegretta6df90f52002-07-19 01:08:59 +0000568 assert(fileage == NULL || fileage != fileage->next);
569 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000570 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000571}
572
Chris Allegretta6df90f52002-07-19 01:08:59 +0000573void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000574{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000575 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000576 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000577 else {
578 int lineno = fileptr->prev->lineno;
579
580 assert(fileptr != fileptr->next);
581 for (; fileptr != NULL; fileptr = fileptr->next)
582 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000583 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000584}
585
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000586/* Print one usage string to the screen, removes lots of duplicate
Chris Allegretta6df90f52002-07-19 01:08:59 +0000587 * strings to translate and takes out the parts that shouldn't be
588 * translatable (the flag names). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000589void print1opt(const char *shortflag, const char *longflag,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000590 const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000591{
592 printf(" %s\t", shortflag);
593 if (strlen(shortflag) < 8)
594 printf("\t");
595
596#ifdef HAVE_GETOPT_LONG
597 printf("%s\t", longflag);
598 if (strlen(longflag) < 8)
599 printf("\t\t");
600 else if (strlen(longflag) < 16)
601 printf("\t");
602#endif
603
604 printf("%s\n", desc);
605}
606
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000607void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000608{
609#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000610 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
611 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000612#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000613 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
614 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000615#endif /* HAVE_GETOPT_LONG */
616
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000617 print1opt("-h, -?", "--help", _("Show this message"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000618 print1opt(_("+LINE"), "", _("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000619#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000620 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000621 print1opt("-D", "--dos", _("Write file in DOS format"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000622#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000623#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000624 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000625#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000626#ifdef ENABLE_NANORC
627 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
628#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000629 print1opt("-K", "--keypad", _("Use alternate keypad routines"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000630#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000631 print1opt("-M", "--mac", _("Write file in Mac format"));
632 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000633#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000634#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000635 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000636#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000637#ifdef HAVE_REGEX_H
638 print1opt("-R", "--regexp", _("Do regular expression searches"));
639#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000640#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000641 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000642#endif
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000643 print1opt(_("-T [num]"), _("--tabsize=[num]"), _("Set width of a tab to num"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000644 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000645#ifdef ENABLE_COLOR
646 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
647#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000648 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000649#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000650 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
651 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000652#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000653 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
Chris Allegretta84de5522001-04-12 14:51:48 +0000654#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000655#ifdef NCURSES_MOUSE_VERSION
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000656 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000657#endif
658#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000659#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000660 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000661#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000662 print1opt("-p", "--pico", _("Emulate Pico as closely as possible"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000663#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000664 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000665#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000666#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000667 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000668#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000669 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
670 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000671#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000672 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000673#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000674 print1opt("-x", "--nohelp", _("Don't show help window"));
675 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000676
677 /* this is a special case */
678 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000679
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000680 exit(0);
681}
682
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000683void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000684{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000685 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000686 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000687 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000688 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000689 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000690
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000691#ifdef DEBUG
692 printf(" --enable-debug");
693#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000694#ifdef NANO_EXTRA
695 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000696#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000697#ifdef NANO_SMALL
698 printf(" --enable-tiny");
699#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000700#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000701 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000702#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000703#ifdef DISABLE_HELP
704 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000705#endif
706#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000707 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000708#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000709#ifdef DISABLE_MOUSE
710 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000711#endif
Chris Allegretta2a15c582002-10-25 01:51:13 +0000712#ifndef ENABLE_NLS
713 printf(" --disable-nls");
714#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000715#ifdef DISABLE_OPERATINGDIR
716 printf(" --disable-operatingdir");
717#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000718#ifdef DISABLE_SPELLER
719 printf(" --disable-speller");
720#endif
721#ifdef DISABLE_TABCOMP
722 printf(" --disable-tabcomp");
723#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000724#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000725#ifdef DISABLE_WRAPPING
726 printf(" --disable-wrapping");
727#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000728#ifdef DISABLE_ROOTWRAP
729 printf(" --disable-wrapping-as-root");
730#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000731#ifdef ENABLE_COLOR
732 printf(" --enable-color");
733#endif
734#ifdef ENABLE_MULTIBUFFER
735 printf(" --enable-multibuffer");
736#endif
737#ifdef ENABLE_NANORC
738 printf(" --enable-nanorc");
739#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000740#ifdef USE_SLANG
741 printf(" --with-slang");
742#endif
743 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000744}
745
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000746/* Stuff we do when we abort from programs and want to clean up the
747 * screen. This doesn't do much right now. */
748void do_early_abort(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000749{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000750 blank_statusbar_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000751}
752
753int no_help(void)
754{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000755 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000756}
757
Chris Allegrettad865da12002-07-29 23:46:38 +0000758#if defined(DISABLE_JUSTIFY) || defined(DISABLE_SPELLER) || defined(DISABLE_HELP) || defined(NANO_SMALL)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000759void nano_disabled_msg(void)
760{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000761 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000762}
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000763#endif
Chris Allegrettaff269f82000-12-01 18:46:01 +0000764
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000765#ifndef NANO_SMALL
766static int pid; /* This is the PID of the newly forked process
767 * below. It must be global since the signal
768 * handler needs it. */
769
770RETSIGTYPE cancel_fork(int signal)
771{
772 if (kill(pid, SIGKILL)==-1) nperror("kill");
773}
774
775int open_pipe(const char *command)
776{
777 int fd[2];
778 FILE *f;
779 struct sigaction oldaction, newaction;
780 /* original and temporary handlers for SIGINT */
781#ifdef _POSIX_VDISABLE
782 struct termios term, newterm;
783#endif /* _POSIX_VDISABLE */
784 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000785 /* cancel_sigs == 1 means that sigaction() failed without changing
786 * the signal handlers. cancel_sigs == 2 means the signal handler
787 * was changed, but the tcsetattr didn't succeed.
788 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000789 * I use this variable since it is important to put things back when
790 * we finish, even if we get errors. */
791
792 /* Make our pipes. */
793
794 if (pipe(fd) == -1) {
795 statusbar(_("Could not pipe"));
796 return 1;
797 }
798
799 /* Fork a child. */
800
801 if ((pid = fork()) == 0) {
802 close(fd[0]);
803 dup2(fd[1], fileno(stdout));
804 dup2(fd[1], fileno(stderr));
805 /* If execl() returns at all, there was an error. */
806
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000807 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000808 exit(0);
809 }
810
811 /* Else continue as parent. */
812
813 close(fd[1]);
814
815 if (pid == -1) {
816 close(fd[0]);
817 statusbar(_("Could not fork"));
818 return 1;
819 }
820
821 /* Before we start reading the forked command's output, we set
822 * things up so that ^C will cancel the new process. */
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000823 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000824 cancel_sigs = 1;
825 nperror("sigaction");
826 } else {
827 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000828 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000829 cancel_sigs = 1;
830 nperror("sigaction");
831 }
832 }
833 /* Note that now oldaction is the previous SIGINT signal handler,
834 * to be restored later. */
835
836 /* See if the platform supports disabling individual control
837 * characters. */
838#ifdef _POSIX_VDISABLE
839 if (!cancel_sigs && tcgetattr(0, &term) == -1) {
840 cancel_sigs = 2;
841 nperror("tcgetattr");
842 }
843 if (!cancel_sigs) {
844 newterm = term;
845 /* Grab oldterm's VINTR key :-) */
846 newterm.c_cc[VINTR] = oldterm.c_cc[VINTR];
847 if (tcsetattr(0, TCSANOW, &newterm) == -1) {
848 cancel_sigs = 2;
849 nperror("tcsetattr");
850 }
851 }
852#endif /* _POSIX_VDISABLE */
853
854 f = fdopen(fd[0], "rb");
855 if (!f)
856 nperror("fdopen");
857
858 read_file(f, "stdin", 0);
859 /* if multibuffer mode is on, we could be here in view mode; if so,
860 don't set the modification flag */
861 if (!ISSET(VIEW_MODE))
862 set_modified();
863
864 if (wait(NULL) == -1)
865 nperror("wait");
866
867#ifdef _POSIX_VDISABLE
868 if (!cancel_sigs && tcsetattr(0, TCSANOW, &term) == -1)
869 nperror("tcsetattr");
870#endif /* _POSIX_VDISABLE */
871
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000872 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000873 nperror("sigaction");
874
875 return 0;
876}
877#endif /* NANO_SMALL */
878
879#ifndef DISABLE_MOUSE
880#ifdef NCURSES_MOUSE_VERSION
881void do_mouse(void)
882{
883 MEVENT mevent;
884 int currslen;
885 const shortcut *s = currshortcut;
886
887 if (getmouse(&mevent) == ERR)
888 return;
889
890 /* If mouse not in edit or bottom window, return */
891 if (wenclose(edit, mevent.y, mevent.x)) {
892
893 /* Don't let people screw with the marker when they're in a
894 * subfunction. */
895 if (currshortcut != main_list)
896 return;
897
898 /* Subtract out size of topwin. Perhaps we need a constant
899 * somewhere? */
900 mevent.y -= 2;
901
902 /* Selecting where the cursor is sets the mark. Selecting
903 * beyond the line length with the cursor at the end of the line
904 * sets the mark as well. */
905 if ((mevent.y == current_y) &&
906 ((mevent.x == current_x) || (current_x == strlen(current->data)
907 && (mevent.x >
908 strlen(current->data))))) {
909 if (ISSET(VIEW_MODE)) {
910 print_view_warning();
911 return;
912 }
913 do_mark();
914 } else if (mevent.y > current_y) {
915 while (mevent.y > current_y) {
916 if (current->next != NULL)
917 current = current->next;
918 else
919 break;
920 current_y++;
921 }
922 } else if (mevent.y < current_y) {
923 while (mevent.y < current_y) {
924 if (current->prev != NULL)
925 current = current->prev;
926 else
927 break;
928 current_y--;
929 }
930 }
931 current_x = actual_x(current, mevent.x);
932 placewewant = current_x;
933 update_cursor();
934 edit_refresh();
935 } else if (wenclose(bottomwin, mevent.y, mevent.x) && !ISSET(NO_HELP)) {
936 int i, k;
937
938 if (currshortcut == main_list)
939 currslen = MAIN_VISIBLE;
940 else
941 currslen = length_of_list(currshortcut);
942
943 if (currslen < 2)
944 k = COLS / 6;
945 else
946 k = COLS / ((currslen + (currslen %2)) / 2);
947
948 /* Determine what shortcut list was clicked */
949 mevent.y -= (editwinrows + 3);
950
951 if (mevent.y < 0) /* They clicked on the statusbar */
952 return;
953
954 /* Don't select stuff beyond list length */
955 if (mevent.x / k >= currslen)
956 return;
957
958 for (i = 0; i < (mevent.x / k) * 2 + mevent.y; i++)
959 s = s->next;
960
961 /* And ungetch that value */
962 ungetch(s->val);
963
964 /* And if it's an alt-key sequence, we should probably send alt
965 too ;-) */
966 if (s->val >= 'a' && s->val <= 'z')
967 ungetch(27);
968 }
969}
970#endif
971#endif
972
Chris Allegretta6df90f52002-07-19 01:08:59 +0000973/* The user typed a printable character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000974void do_char(char ch)
975{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000976 size_t current_len = strlen(current->data);
977#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
978 int refresh = 0;
979 /* Do we have to run edit_refresh(), or can we get away with
980 * update_line()? */
981#endif
982
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000983 /* magic-line: when a character is inserted on the current magic line,
984 * it means we need a new one! */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000985 if (filebot == current && current->data[0] == '\0') {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000986 new_magicline();
Chris Allegretta28a0f892000-07-05 22:47:54 +0000987 fix_editbot();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000988 }
989
Chris Allegretta6df90f52002-07-19 01:08:59 +0000990 /* more dangerousness fun =) */
991 current->data = nrealloc(current->data, current_len + 2);
992 assert(current_x <= current_len);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000993 memmove(&current->data[current_x + 1],
994 &current->data[current_x],
Chris Allegretta6df90f52002-07-19 01:08:59 +0000995 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000996 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000997 totsize++;
998 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000999
Chris Allegretta6df90f52002-07-19 01:08:59 +00001000#ifndef NANO_SMALL
1001 /* note that current_x has not yet been incremented */
1002 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001003 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +00001004#endif
1005
Chris Allegretta6df90f52002-07-19 01:08:59 +00001006 do_right();
1007
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001008#ifndef DISABLE_WRAPPING
Chris Allegrettadffa2072002-07-24 01:02:26 +00001009 if (!ISSET(NO_WRAP) && ch != '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001010 refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001011#endif
1012
Chris Allegretta6df90f52002-07-19 01:08:59 +00001013#ifdef ENABLE_COLOR
1014 refresh = 1;
1015#endif
1016
1017#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
1018 if (refresh)
1019 edit_refresh();
1020#endif
1021
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001022 check_statblank();
1023 UNSET(KEEP_CUTBUFFER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001024}
1025
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001026int do_backspace(void)
1027{
1028 int refresh = 0;
1029 if (current_x > 0) {
1030 assert(current_x <= strlen(current->data));
1031 /* Let's get dangerous */
1032 memmove(&current->data[current_x - 1], &current->data[current_x],
1033 strlen(current->data) - current_x + 1);
1034#ifdef DEBUG
1035 fprintf(stderr, _("current->data now = \"%s\"\n"), current->data);
1036#endif
1037 align(&current->data);
1038#ifndef NANO_SMALL
1039 if (current_x <= mark_beginx && mark_beginbuf == current)
1040 mark_beginx--;
1041#endif
1042 do_left();
1043#ifdef ENABLE_COLOR
1044 refresh = 1;
1045#endif
1046 } else {
1047 filestruct *previous;
1048 const filestruct *tmp;
1049
1050 if (current == fileage)
1051 return 0; /* Can't delete past top of file */
1052
1053 previous = current->prev;
1054 current_x = strlen(previous->data);
1055 placewewant = strlenpt(previous->data);
1056#ifndef NANO_SMALL
1057 if (current == mark_beginbuf) {
1058 mark_beginx += current_x;
1059 mark_beginbuf = previous;
1060 }
1061#endif
1062 previous->data = nrealloc(previous->data,
1063 current_x + strlen(current->data) + 1);
1064 strcpy(previous->data + current_x, current->data);
1065
1066 unlink_node(current);
1067 delete_node(current);
1068 tmp = current;
1069 current = (previous->next ? previous->next : previous);
1070 renumber(current);
1071 /* We had to renumber before doing update_line. */
1072 if (tmp == edittop)
1073 page_up();
1074
1075 /* Ooops, sanity check */
1076 if (tmp == filebot) {
1077 filebot = current;
1078 editbot = current;
1079
1080 /* Recreate the magic line if we're deleting it AND if the
1081 line we're on now is NOT blank. if it is blank we
1082 can just use IT for the magic line. This is how Pico
1083 appears to do it, in any case. */
1084 if (current->data[0] != '\0') {
1085 new_magicline();
1086 fix_editbot();
1087 }
1088 }
1089
1090 current = previous;
1091 if (current_y > 0)
1092 current_y--;
1093 totlines--;
1094#ifdef DEBUG
1095 fprintf(stderr, _("After, data = \"%s\"\n"), current->data);
1096#endif
1097 UNSET(KEEP_CUTBUFFER);
1098 refresh = 1;
1099 }
1100
1101 totsize--;
1102 set_modified();
1103 if (refresh)
1104 edit_refresh();
1105 return 1;
1106}
1107
1108int do_delete(void)
1109{
1110 int refresh = 0;
1111
1112 /* blbf -> blank line before filebot (see below) */
1113 int blbf = 0;
1114
1115 if (current->next == filebot && current->data[0] == '\0')
1116 blbf = 1;
1117
1118 placewewant = xplustabs();
1119
1120 if (current_x != strlen(current->data)) {
1121 /* Let's get dangerous */
1122 memmove(&current->data[current_x], &current->data[current_x + 1],
1123 strlen(current->data) - current_x);
1124
1125 align(&current->data);
1126#ifdef ENABLE_COLOR
1127 refresh = 1;
1128#endif
1129 } else if (current->next != NULL && (current->next != filebot || blbf)) {
1130 /* We can delete the line before filebot only if it is blank: it
1131 becomes the new magic line then. */
1132
1133 filestruct *foo;
1134
1135 current->data = nrealloc(current->data,
1136 strlen(current->data) +
1137 strlen(current->next->data) + 1);
1138 strcat(current->data, current->next->data);
1139
1140 foo = current->next;
1141 if (filebot == foo) {
1142 filebot = current;
1143 editbot = current;
1144 }
1145
1146 unlink_node(foo);
1147 delete_node(foo);
1148 renumber(current);
1149 totlines--;
1150 refresh = 1;
1151 } else
1152 return 0;
1153
1154 totsize--;
1155 set_modified();
1156 UNSET(KEEP_CUTBUFFER);
1157 update_line(current, current_x);
1158 if (refresh)
1159 edit_refresh();
1160 return 1;
1161}
1162
1163int do_tab(void)
1164{
1165 do_char('\t');
1166 return 1;
1167}
1168
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001169/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001170int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001171{
Chris Allegrettae3167732001-03-18 16:59:34 +00001172 filestruct *newnode;
Chris Allegretta68532c32001-09-17 13:49:33 +00001173 char *tmp;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001174
Chris Allegretta6df90f52002-07-19 01:08:59 +00001175 newnode = make_new_node(current);
1176 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001177 tmp = &current->data[current_x];
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001178
Chris Allegrettaff989832001-09-17 13:48:00 +00001179#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001180 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001181 if (ISSET(AUTOINDENT)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001182 int extra = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001183 const char *spc = current->data;
1184
1185 while (*spc == ' ' || *spc == '\t') {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001186 extra++;
1187 spc++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001188 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001189 /* If current_x < extra, then we are breaking the line in the
1190 * indentation. Autoindenting should add only current_x
1191 * characters of indentation. */
Chris Allegrettadab017e2002-04-23 10:56:06 +00001192 if (current_x < extra)
1193 extra = current_x;
1194 else
1195 current_x = extra;
1196 totsize += extra;
1197
1198 newnode->data = charalloc(strlen(tmp) + extra + 1);
1199 strncpy(newnode->data, current->data, extra);
1200 strcpy(&newnode->data[extra], tmp);
Chris Allegrettaff989832001-09-17 13:48:00 +00001201 } else
1202#endif
1203 {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001204 current_x = 0;
Chris Allegretta88b09152001-05-17 11:35:43 +00001205 newnode->data = charalloc(strlen(tmp) + 1);
Chris Allegrettae3167732001-03-18 16:59:34 +00001206 strcpy(newnode->data, tmp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001207 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001208 *tmp = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001209
Chris Allegretta6df90f52002-07-19 01:08:59 +00001210 if (current->next == NULL) {
Chris Allegrettae3167732001-03-18 16:59:34 +00001211 filebot = newnode;
1212 editbot = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001213 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001214 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001215
1216 totsize++;
1217 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001218 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001219 align(&current->data);
1220
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001221 /* The logic here is as follows:
1222 * -> If we are at the bottom of the buffer, we want to recenter
Chris Allegretta88520c92001-05-05 17:45:54 +00001223 * (read: rebuild) the screen and forcibly move the cursor.
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001224 * -> otherwise, we want simply to redraw the screen and update
1225 * where we think the cursor is.
1226 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001227 if (current_y == editwinrows - 1) {
Chris Allegretta234a34d2000-07-29 04:33:38 +00001228 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
Chris Allegretta6df90f52002-07-19 01:08:59 +00001303 assert(current != 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;
1532 /* If !temp->next, then temp is the last line of the file, so we
Chris Allegretta81dea022002-09-21 02:19:45 +00001533 * must set filebot. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001534 if (temp->next)
1535 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) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001626 if (findnextstr(TRUE, FALSE, fileage, beginx_top, word) != NULL) {
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
Chris Allegretta6df90f52002-07-19 01:08:59 +00001681/* Integrated spell checking using 'spell' program. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001682int do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001683{
Chris Allegretta271e9722000-11-10 18:15:43 +00001684 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001685 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001686 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd;
1687 pid_t pid_spell, pid_sort, pid_uniq;
1688 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001689
Chris Allegretta271e9722000-11-10 18:15:43 +00001690 /* Create a pipe to spell program */
1691
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001692 if (pipe(spell_fd) == -1)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001693 return FALSE;
1694
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001695 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegretta271e9722000-11-10 18:15:43 +00001696 /* A new process to run spell in */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001697
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001698 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001699
1700 /* Child continues, (i.e. future spell process) */
1701
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001702 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001703
Chris Allegretta271e9722000-11-10 18:15:43 +00001704 /* replace the standard in with the tempfile */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001705 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1) {
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001706 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001707 exit(1);
1708 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001709 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001710 close(tempfile_fd);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001711 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001712 exit(1);
1713 }
1714 close(tempfile_fd);
1715
1716 /* send spell's standard out to the pipe */
1717
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001718 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
1719 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001720 exit(1);
1721 }
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001722 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001723
1724 /* Start spell program, we are using the PATH here!?!? */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001725 execlp("spell", "spell", NULL);
1726
Chris Allegretta271e9722000-11-10 18:15:43 +00001727 /* Should not be reached, if spell is found!!! */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001728
Chris Allegretta271e9722000-11-10 18:15:43 +00001729 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001730 }
1731
1732 /* Parent continues here */
1733
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001734 close(spell_fd[1]);
1735
1736 if (pipe(sort_fd) == -1)
1737 return FALSE;
1738
1739 /* A new process to run sort in */
1740
1741 if ((pid_sort = fork()) == 0) {
1742
1743 /* Child continues, (i.e. future spell process) */
1744 /* replace the standard in with output of the old pipe */
1745 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO) {
1746 close(spell_fd[0]);
1747 close(sort_fd[1]);
1748 exit(1);
1749 }
1750 close(spell_fd[0]);
1751
1752 /* send sort's standard out to the new pipe */
1753
1754 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
1755 close(sort_fd[1]);
1756 exit(1);
1757 }
1758 close(sort_fd[1]);
1759
1760 /* Start sort program. Use -f to remove mixed case without having
1761 to have ANOTHER pipe for tr. If this isn't portable, let me know. */
1762 execlp("sort", "sort", "-f", NULL);
1763
1764 /* Should not be reached, if sort is found */
1765
1766 exit(1);
1767 }
1768
1769 close(sort_fd[1]);
1770
1771 /* And one more for uniq! */
1772
1773 if (pipe(uniq_fd) == -1)
1774 return FALSE;
1775
1776 /* A new process to run uniq in */
1777
1778 if ((pid_uniq = fork()) == 0) {
1779
1780 /* Child continues, (i.e. future uniq process) */
1781 /* replace the standard in with output of the old pipe */
1782 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO) {
1783 close(sort_fd[0]);
1784 close(uniq_fd[1]);
1785 exit(1);
1786 }
1787 close(sort_fd[0]);
1788
1789 /* send uniq's standard out to the new pipe */
1790
1791 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
1792 close(uniq_fd[1]);
1793 exit(1);
1794 }
1795 close(uniq_fd[1]);
1796
1797 /* Start uniq program, we are using PATH */
1798 execlp("uniq", "uniq", NULL);
1799
1800 /* Should not be reached, if uniq is found */
1801
1802 exit(1);
1803 }
1804
1805 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001806
1807 /* Child process was not forked successfully */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001808
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001809 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1810 close(uniq_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001811 return FALSE;
1812 }
1813
Chris Allegretta271e9722000-11-10 18:15:43 +00001814 /* Get system pipe buffer size */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001815
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001816 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1817 close(uniq_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001818 return FALSE;
Chris Allegretta271e9722000-11-10 18:15:43 +00001819 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001820
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001821 /* Read-in the returned spelling errors */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001822
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001823 read_buff_read = 0;
1824 read_buff_size = pipe_buff_size + 1;
1825 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001826
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001827 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001828 read_buff_read += bytesread;
1829 read_buff_size += pipe_buff_size;
1830 read_buff = read_buff_ptr = nrealloc(read_buff, read_buff_size);
1831 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001832
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001833 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001834
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001835 *read_buff_ptr = (char) NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001836 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001837
1838 /* Process the spelling errors */
1839
1840 read_buff_word = read_buff_ptr = read_buff;
1841
1842 while (*read_buff_ptr) {
1843
1844 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
1845 *read_buff_ptr = (char) NULL;
1846 if (read_buff_word != read_buff_ptr) {
1847 if (!do_int_spell_fix(read_buff_word)) {
1848 read_buff_word = read_buff_ptr;
1849 break;
1850 }
1851 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001852 read_buff_word = read_buff_ptr + 1;
1853 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001854 read_buff_ptr++;
1855 }
1856
1857 /* special case where last word doesn't end with \n or \r */
1858 if (read_buff_word != read_buff_ptr)
1859 do_int_spell_fix(read_buff_word);
1860
Chris Allegretta271e9722000-11-10 18:15:43 +00001861 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001862 replace_abort();
Chris Allegretta35908f82002-12-10 00:55:32 +00001863 edit_update(current, current_x);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001864
Chris Allegretta271e9722000-11-10 18:15:43 +00001865 /* Process end of spell process */
1866
Chris Allegretta848f5be2002-12-09 05:49:05 +00001867 waitpid(pid_spell, &spell_status, WNOHANG);
1868 waitpid(pid_sort, &sort_status, WNOHANG);
1869 waitpid(pid_uniq, &uniq_status, WNOHANG);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001870
1871 if (WIFEXITED(spell_status) && WIFEXITED(sort_status)
1872 && WIFEXITED(uniq_status)) {
Chris Allegretta848f5be2002-12-09 05:49:05 +00001873 if (WEXITSTATUS(spell_status) != 0 || WEXITSTATUS(sort_status) != 0
1874 || WEXITSTATUS(uniq_status) != 0)
Chris Allegretta271e9722000-11-10 18:15:43 +00001875 return FALSE;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001876 } else
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001877 return FALSE;
Chris Allegretta271e9722000-11-10 18:15:43 +00001878
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001879 return TRUE;
1880}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001881
Chris Allegretta6df90f52002-07-19 01:08:59 +00001882/* External spell checking. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001883int do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001884{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001885 int alt_spell_status, lineno_cur = current->lineno;
1886 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001887 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001888 char *ptr;
1889 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001890 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001891#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001892 int mark_set = ISSET(MARK_ISSET);
1893 int mbb_lineno_cur = 0;
1894 /* We're going to close the current file, and open the output of
1895 the alternate spell command. The line that mark_beginbuf
1896 points to will be freed, so we save the line number and restore
1897 afterwards. */
1898
1899 if (mark_set) {
1900 mbb_lineno_cur = mark_beginbuf->lineno;
1901 UNSET(MARK_ISSET);
1902 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001903#endif
1904
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001905 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001906
Chris Allegrettae434b452001-01-27 19:25:00 +00001907 /* Set up an argument list to pass the execvp function */
1908 if (spellargs == NULL) {
1909 spellargs = nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001910
Chris Allegrettae434b452001-01-27 19:25:00 +00001911 spellargs[0] = strtok(alt_speller, " ");
1912 while ((ptr = strtok(NULL, " ")) != NULL) {
1913 arglen++;
1914 spellargs = nrealloc(spellargs, arglen * sizeof(char *));
1915 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001916 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001917 spellargs[arglen - 1] = NULL;
1918 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001919 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001920
1921 /* Start a new process for the alternate speller */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001922 if ((pid_spell = fork()) == 0) {
Chris Allegretta88520c92001-05-05 17:45:54 +00001923 /* Start alternate spell program; we are using the PATH here!?!? */
Chris Allegretta169ee842001-01-26 01:57:32 +00001924 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001925
1926 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001927 exit(1);
1928 }
1929
1930 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001931 if (pid_spell < 0)
1932 return FALSE;
1933
1934 /* Wait for alternate speller to complete */
1935
1936 wait(&alt_spell_status);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001937 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001938 return FALSE;
1939
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001940 refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001941 free_filestruct(fileage);
Chris Allegretta56214c62001-09-27 02:46:53 +00001942 global_init(1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001943 open_file(tempfile_name, 0, 1);
Rocco Corsi4dfaf932001-04-20 01:59:55 +00001944
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001945#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001946 if (mark_set) {
1947 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1948 mark_beginbuf = current;
1949 mark_beginx = current_x;
1950 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001951 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001952 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001953#endif
1954
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001955 /* go back to the old position, mark the file as modified, and make
1956 sure that the titlebar is refreshed */
1957 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001958 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001959 clearok(topwin, FALSE);
1960 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001961
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001962 return TRUE;
1963}
1964#endif
1965
1966int do_spell(void)
1967{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001968#ifdef DISABLE_SPELLER
Chris Allegrettaff269f82000-12-01 18:46:01 +00001969 nano_disabled_msg();
1970 return (TRUE);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001971#else
Chris Allegretta271e9722000-11-10 18:15:43 +00001972 char *temp;
1973 int spell_res;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001974
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001975 if ((temp = safe_tempnam(0, "nano.")) == NULL) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001976 statusbar(_("Could not create a temporary filename: %s"),
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001977 strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001978 return 0;
1979 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001980
Chris Allegrettaecc3d7f2001-06-05 23:24:55 +00001981 if (write_file(temp, 1, 0, 0) == -1) {
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001982 statusbar(_("Spell checking failed: unable to write temp file!"));
Chris Allegrettabef12972002-03-06 03:30:40 +00001983 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001984 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001985 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001986
Chris Allegrettae1f14522001-09-19 03:19:43 +00001987#ifdef ENABLE_MULTIBUFFER
1988 /* update the current open_files entry before spell-checking, in case
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001989 any problems occur */
Chris Allegretta48b06702002-02-22 04:30:50 +00001990 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001991#endif
1992
Chris Allegretta271e9722000-11-10 18:15:43 +00001993 if (alt_speller)
1994 spell_res = do_alt_speller(temp);
1995 else
1996 spell_res = do_int_speller(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001997
Chris Allegretta271e9722000-11-10 18:15:43 +00001998 remove(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001999
2000 if (spell_res)
2001 statusbar(_("Finished checking spelling"));
2002 else
2003 statusbar(_("Spell checking failed"));
2004
Chris Allegrettabef12972002-03-06 03:30:40 +00002005 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002006 return spell_res;
2007
Chris Allegrettadbc12b22000-07-03 03:10:14 +00002008#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00002009}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002010
Chris Allegrettad865da12002-07-29 23:46:38 +00002011#if !defined(DISABLE_WRAPPING) && !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002012/* The "indentation" of a line is the white-space between the quote part
2013 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002014size_t indent_length(const char *line)
2015{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002016 size_t len = 0;
2017
2018 assert(line != NULL);
2019 while (*line == ' ' || *line == '\t') {
2020 line++;
2021 len++;
2022 }
2023 return len;
2024}
Chris Allegrettadffa2072002-07-24 01:02:26 +00002025#endif /* !DISABLE_WRAPPING && !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002026
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002027#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00002028/* justify_format() replaces Tab by Space and multiple spaces by 1 (except
2029 * it maintains 2 after a . ! or ?). Note the terminating \0
2030 * counts as a space.
2031 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002032 * If !changes_allowed and justify_format() needs to make a change, it
Chris Allegretta6df90f52002-07-19 01:08:59 +00002033 * returns 1, otherwise returns 0.
2034 *
2035 * If changes_allowed, justify_format() might make line->data
2036 * shorter, and change the actual pointer with null_at().
2037 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002038 * justify_format() will not look at the first skip characters of line.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002039 * skip should be at most strlen(line->data). The skip+1st character must
2040 * not be whitespace. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002041int justify_format(int changes_allowed, filestruct *line, size_t skip)
2042{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002043 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002044
Chris Allegretta6df90f52002-07-19 01:08:59 +00002045 /* These four asserts are assumptions about the input data. */
2046 assert(line != NULL);
2047 assert(line->data != NULL);
2048 assert(skip <= strlen(line->data));
2049 assert(line->data[skip] != ' ' && line->data[skip] != '\t');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002050
Chris Allegretta6df90f52002-07-19 01:08:59 +00002051 back = line->data + skip;
2052 front = back;
2053 for (; *front; front++) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002054 int remove_space = 0;
2055 /* Do we want to remove this space? */
2056
Chris Allegretta6df90f52002-07-19 01:08:59 +00002057 if (*front == '\t') {
2058 if (!changes_allowed)
2059 return 1;
2060 *front = ' ';
2061 }
2062 /* these tests are safe since line->data + skip is not a space */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002063 if (*front == ' ' && *(front-1) == ' ') {
2064 const char *brackets = _("'\")}]>");
2065 const char *punct = _(".?!");
2066 const char *bob = front - 2;
2067
2068 remove_space = 1;
2069 for (bob = front - 2; bob >= line->data + skip; bob--) {
2070 if (strchr(punct, *bob) != NULL) {
2071 remove_space = 0;
2072 break;
2073 }
2074 if (strchr(brackets, *bob) == NULL)
2075 break;
2076 }
2077 }
2078
2079 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002080 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002081 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002082 if (!changes_allowed)
2083 return 1;
2084#ifndef NANO_SMALL
2085 if (mark_beginbuf == line && back - line->data < mark_beginx)
2086 mark_beginx--;
2087#endif
2088 } else {
2089 *back = *front;
2090 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002091 }
2092 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002093
2094 /* Remove spaces from the end of the line, except maintain 1 after a
2095 * sentence punctuation. */
2096 while (line->data < back && *(back-1) == ' ')
2097 back--;
2098 if (line->data < back && *back == ' ' &&
2099 (*(back-1) == '.' || *(back-1) == '!' || *(back-1) == '?'))
2100 back++;
2101 if (!changes_allowed && back != front)
2102 return 1;
2103
2104 /* This assert merely documents a fact about the loop above. */
Chris Allegrettad865da12002-07-29 23:46:38 +00002105 assert(changes_allowed || back == front);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002106
2107 /* Now back is the new end of line->data. */
2108 if (back != front) {
2109 totsize += back - line->data - strlen(line->data);
2110 null_at(&line->data, back - line->data);
2111#ifndef NANO_SMALL
2112 if (mark_beginbuf == line && back - line->data < mark_beginx)
2113 mark_beginx = back - line->data;
2114#endif
2115 }
2116 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002117}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002118
2119/* The "quote part" of a line is the largest initial substring matching
2120 * the quote string. This function returns the length of the quote part
2121 * of the given line.
2122 *
2123 * Note that if !HAVE_REGEX_H then we match concatenated copies of
2124 * quotestr. */
2125#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002126size_t quote_length(const char *line, const regex_t *qreg)
2127{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002128 regmatch_t matches;
2129 int rc = regexec(qreg, line, 1, &matches, 0);
2130
2131 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
2132 return 0;
2133 /* matches.rm_so should be 0, since the quote string should start with
2134 * the caret ^. */
2135 return matches.rm_eo;
2136}
2137#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002138size_t quote_length(const char *line)
2139{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002140 size_t qdepth = 0;
2141 size_t qlen = strlen(quotestr);
2142
2143 /* Compute quote depth level */
2144 while (!strcmp(line + qdepth, quotestr))
2145 qdepth += qlen;
2146 return qdepth;
2147}
2148#endif /* !HAVE_REGEX_H */
2149
Chris Allegretta6df90f52002-07-19 01:08:59 +00002150/* a_line and b_line are lines of text. The quotation part of a_line is
2151 * the first a_quote characters. Check that the quotation part of
2152 * b_line is the same. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002153int quotes_match(const char *a_line, size_t a_quote,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002154 IFREG(const char *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002155{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002156 /* Here is the assumption about a_quote: */
2157 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00002158 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00002159 !strncmp(a_line, b_line, a_quote);
2160}
2161
2162/* We assume a_line and b_line have no quote part. Then, we return whether
2163 * b_line could follow a_line in a paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002164size_t indents_match(const char *a_line, size_t a_indent,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002165 const char *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002166{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002167 assert(a_indent == indent_length(a_line));
2168 assert(b_indent == indent_length(b_line));
2169
2170 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2171}
2172
2173/* Put the next par_len lines, starting with first_line, in the cut
2174 * buffer. We assume there are enough lines after first_line. We leave
2175 * copies of the lines in place, too. We return the new copy of
2176 * first_line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002177filestruct *backup_lines(filestruct *first_line, size_t par_len,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002178 size_t quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002179{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002180 /* We put the original lines, not copies, into the cut buffer, just
2181 * out of a misguided sense of consistency, so if you un-cut, you
2182 * get the actual same paragraph back, not a copy. */
2183 filestruct *alice = first_line;
2184
2185 set_modified();
2186 cutbuffer = NULL;
2187 for(; par_len > 0; par_len--) {
2188 filestruct *bob = copy_node(alice);
2189
2190 if (alice == first_line)
2191 first_line = bob;
2192 if (alice == current)
2193 current = bob;
2194 if (alice == edittop)
2195 edittop = bob;
2196#ifndef NANO_SMALL
2197 if (alice == mark_beginbuf)
2198 mark_beginbuf = bob;
2199#endif
2200 justify_format(1, bob,
2201 quote_len + indent_length(bob->data + quote_len));
2202
2203 assert(alice != NULL && bob != NULL);
2204 add_to_cutbuffer(alice);
2205 splice_node(bob->prev, bob, bob->next);
2206 alice = bob->next;
2207 }
2208 return first_line;
2209}
2210
2211/* We are trying to break a chunk off line. We find the last space such
2212 * that the display length to there is at most goal + 1. If there is
2213 * no such space, and force is not 0, then we find the first space.
2214 * Anyway, we then take the last space in that group of spaces. The
2215 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002216int break_line(const char *line, int goal, int force)
2217{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002218 /* Note that we use int instead of size_t, since goal is at most COLS,
2219 * the screen width, which will always be reasonably small. */
2220 int space_loc = -1;
2221 /* Current tentative return value. Index of the last space we
2222 * found with short enough display width. */
2223 int cur_loc = 0;
2224 /* Current index in line */
2225
2226 assert(line != NULL);
2227 for(; *line != '\0' && goal >= 0; line++, cur_loc++) {
2228 if (*line == ' ')
2229 space_loc = cur_loc;
2230 assert(*line != '\t');
2231
Chris Allegrettacf287c82002-07-20 13:57:41 +00002232 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002233 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002234 else
2235 goal--;
2236 }
2237 if (goal >= 0)
2238 /* In fact, the whole line displays shorter than goal. */
2239 return cur_loc;
2240 if (space_loc == -1) {
2241 /* No space found short enough. */
2242 if (force)
2243 for(; *line != '\0'; line++, cur_loc++)
2244 if (*line == ' ' && *(line + 1) != ' ')
2245 return cur_loc;
2246 return -1;
2247 }
2248 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002249 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002250 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2251 *(line - cur_loc + space_loc + 1) == '\0')
2252 space_loc++;
2253 return space_loc;
2254}
2255#endif /* !DISABLE_JUSTIFY */
2256
2257/* This function justifies the current paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002258int do_justify(void)
2259{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002260#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +00002261 nano_disabled_msg();
2262 return 1;
2263#else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002264
Chris Allegretta6df90f52002-07-19 01:08:59 +00002265/* To explain the justifying algorithm, I first need to define some
2266 * phrases about paragraphs and quotation:
2267 * A line of text consists of a "quote part", followed by an
2268 * "indentation part", followed by text. The functions quote_length()
2269 * and indent_length() calculate these parts.
2270 *
2271 * A line is "part of a paragraph" if it has a part not in the quote
2272 * part or the indentation.
2273 *
2274 * A line is "the beginning of a paragraph" if it is part of a paragraph
2275 * and
2276 * 1) it is the top line of the file, or
2277 * 2) the line above it is not part of a paragraph, or
2278 * 3) the line above it does not have precisely the same quote
2279 * part, or
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002280 * 4) the indentation of this line is not an initial substring of the
Chris Allegretta6df90f52002-07-19 01:08:59 +00002281 * indentation of the previous line, or
2282 * 5) this line has no quote part and some indentation, and
2283 * AUTOINDENT is not set.
2284 * The reason for number 5) is that if AUTOINDENT is not set, then an
2285 * indented line is expected to start a paragraph, like in books. Thus,
2286 * nano can justify an indented paragraph only if AUTOINDENT is turned
2287 * on.
2288 *
2289 * A contiguous set of lines is a "paragraph" if each line is part of
2290 * a paragraph and only the first line is the beginning of a paragraph.
Chris Allegrettad4fa0d32002-03-05 19:55:55 +00002291 */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002292
Chris Allegretta6df90f52002-07-19 01:08:59 +00002293 size_t quote_len;
2294 /* Length of the initial quotation of the paragraph we justify. */
2295 size_t par_len;
2296 /* Number of lines in that paragraph. */
2297 filestruct *first_mod_line = NULL;
2298 /* Will be the first line of the resulting justified paragraph
2299 * that differs from the original. For restoring after uncut. */
2300 filestruct *last_par_line = current;
2301 /* Will be the last line of the result, also for uncut. */
2302 filestruct *cutbuffer_save = cutbuffer;
2303 /* When the paragraph gets modified, all lines from the changed
2304 * one down are stored in the cut buffer. We back up the original
2305 * to restore it later. */
2306
2307 /* We save these global variables to be restored if the user
2308 * unjustifies. Note we don't need to save totlines. */
2309 int current_x_save = current_x;
2310 int current_y_save = current_y;
2311 filestruct *current_save = current;
2312 int flags_save = flags;
2313 long totsize_save = totsize;
2314 filestruct *edittop_save = edittop;
2315 filestruct *editbot_save = editbot;
2316#ifndef NANO_SMALL
2317 filestruct *mark_beginbuf_save = mark_beginbuf;
2318 int mark_beginx_save = mark_beginx;
2319#endif
2320
2321 size_t indent_len; /* generic indentation length */
2322 filestruct *line; /* generic line of text */
2323 size_t i; /* generic loop variable */
2324
2325#ifdef HAVE_REGEX_H
2326 regex_t qreg; /* qreg is the compiled quotation regexp.
Chris Allegrettad865da12002-07-29 23:46:38 +00002327 * We no longer care about quotestr. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002328 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2329
2330 if (rc) {
2331 size_t size = regerror(rc, &qreg, NULL, 0);
2332 char *strerror = charalloc(size);
2333
2334 regerror(rc, &qreg, strerror, size);
2335 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2336 free(strerror);
2337 return -1;
2338 }
2339#endif
2340
2341 /* Here is an assumption that is always true anyway. */
2342 assert(current != NULL);
2343
2344/* Here we find the first line of the paragraph to justify. If the
2345 * current line is in a paragraph, then we move back to the first line.
2346 * Otherwise we move down to the first line that is in a paragraph. */
2347 quote_len = quote_length(IFREG(current->data, &qreg));
2348 indent_len = indent_length(current->data + quote_len);
2349
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002350 current_x = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002351 if (current->data[quote_len + indent_len] != '\0') {
2352 /* This line is part of a paragraph. So we must search back to
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002353 * the first line of this paragraph. First we check items 1) and
2354 * 3) above. */
2355 while (current->prev && quotes_match(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002356 quote_len, IFREG(current->prev->data, &qreg))) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002357 size_t temp_id_len =
Chris Allegretta6df90f52002-07-19 01:08:59 +00002358 indent_length(current->prev->data + quote_len);
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002359 /* The indentation length of the previous line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002360
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002361 /* Is this line the beginning of a paragraph, according to
2362 items 2), 5), or 4) above? If so, stop. */
2363 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
2364 (quote_len == 0 && indent_len > 0
2365#ifndef NANO_SMALL
2366 && !ISSET(AUTOINDENT)
2367#endif
2368 ) ||
2369 !indents_match(current->prev->data + quote_len,
2370 temp_id_len, current->data + quote_len, indent_len))
2371 break;
2372 indent_len = temp_id_len;
2373 current = current->prev;
2374 current_y--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00002375 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002376 } else {
Chris Allegrettad865da12002-07-29 23:46:38 +00002377 /* This line is not part of a paragraph. Move down until we get
2378 * to a non "blank" line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002379 do {
2380 /* There is no next paragraph, so nothing to justify. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002381 if (current->next == NULL) {
2382 placewewant = 0;
2383 if (current_y > editwinrows - 4)
2384 edit_update(current, CENTER);
2385 else
2386 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002387 return 0;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002388 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002389 current = current->next;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002390 current_y++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002391 quote_len = quote_length(IFREG(current->data, &qreg));
2392 indent_len = indent_length(current->data + quote_len);
2393 } while (current->data[quote_len + indent_len] == '\0');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002394 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002395/* Now current is the first line of the paragraph, and quote_len
2396 * is the quotation length of that line. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002397
Chris Allegretta6df90f52002-07-19 01:08:59 +00002398/* Next step, compute par_len, the number of lines in this paragraph. */
2399 line = current;
2400 par_len = 1;
2401 indent_len = indent_length(line->data + quote_len);
2402
2403 while (line->next && quotes_match(current->data, quote_len,
2404 IFREG(line->next->data, &qreg))) {
2405 size_t temp_id_len = indent_length(line->next->data + quote_len);
2406
2407 if (!indents_match(line->data + quote_len, indent_len,
2408 line->next->data + quote_len, temp_id_len) ||
2409 line->next->data[quote_len + temp_id_len] == '\0' ||
2410 (quote_len == 0 && temp_id_len > 0
2411#ifndef NANO_SMALL
2412 && !ISSET(AUTOINDENT)
2413#endif
2414 ))
2415 break;
2416 indent_len = temp_id_len;
2417 line = line->next;
2418 par_len++;
2419 }
2420#ifdef HAVE_REGEX_H
2421 /* We no longer need to check quotation. */
2422 regfree(&qreg);
2423#endif
2424/* Now par_len is the number of lines in this paragraph. Should never
2425 * call quotes_match() or quote_length() again. */
2426
2427/* Next step, we loop through the lines of this paragraph, justifying
2428 * each one individually. */
2429 for(; par_len > 0; current_y++, par_len--) {
2430 size_t line_len;
2431 size_t display_len;
2432 /* The width of current in screen columns. */
2433 int break_pos;
2434 /* Where we will break the line. */
2435
2436 indent_len = indent_length(current->data + quote_len) +
2437 quote_len;
2438 /* justify_format() removes excess spaces from the line, and
2439 * changes tabs to spaces. The first argument, 0, means don't
2440 * change the line, just say whether there are changes to be
2441 * made. If there are, we do backup_lines(), which copies the
2442 * original paragraph to the cutbuffer for unjustification, and
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002443 * then calls justify_format() on the remaining lines. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002444 if (first_mod_line == NULL &&
2445 justify_format(0, current, indent_len))
2446 first_mod_line = backup_lines(current, par_len, quote_len);
2447
2448 line_len = strlen(current->data);
2449 display_len = strlenpt(current->data);
2450
2451 if (display_len > fill) {
2452 /* The line is too long. Try to wrap it to the next. */
2453 break_pos = break_line(current->data + indent_len,
2454 fill - strnlenpt(current->data, indent_len),
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002455 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002456 if (break_pos == -1 || break_pos + indent_len == line_len)
2457 /* We can't break the line, or don't need to, so just go
2458 * on to the next. */
2459 goto continue_loc;
2460 break_pos += indent_len;
2461 assert(break_pos < line_len);
2462 /* If we haven't backed up the paragraph, do it now. */
2463 if (first_mod_line == NULL)
2464 first_mod_line = backup_lines(current, par_len, quote_len);
2465 if (par_len == 1) {
2466 /* There is no next line in this paragraph. We make a new
2467 * line and copy text after break_pos into it. */
2468 splice_node(current, make_new_node(current),
2469 current->next);
2470 current->next->data = charalloc(indent_len + line_len -
2471 break_pos);
2472 strncpy(current->next->data, current->data,
2473 indent_len);
2474 strcpy(current->next->data + indent_len,
2475 current->data + break_pos + 1);
2476 assert(strlen(current->next->data) ==
2477 indent_len + line_len - break_pos - 1);
2478 totlines++;
2479 totsize += indent_len;
2480 par_len++;
2481 } else {
2482 size_t next_line_len = strlen(current->next->data);
2483
2484 indent_len = quote_len +
2485 indent_length(current->next->data + quote_len);
2486 current->next->data = (char *)nrealloc(current->next->data,
2487 sizeof(char) * (next_line_len + line_len -
2488 break_pos + 1));
2489
2490 memmove(current->next->data + indent_len + line_len - break_pos,
2491 current->next->data + indent_len,
2492 next_line_len - indent_len + 1);
2493 strcpy(current->next->data + indent_len,
2494 current->data + break_pos + 1);
2495 current->next->data[indent_len + line_len - break_pos - 1]
2496 = ' ';
2497#ifndef NANO_SMALL
2498 if (mark_beginbuf == current->next) {
2499 if (mark_beginx < indent_len)
2500 mark_beginx = indent_len;
2501 mark_beginx += line_len - break_pos;
2502 }
2503#endif
2504 }
2505#ifndef NANO_SMALL
2506 if (mark_beginbuf == current && mark_beginx > break_pos) {
2507 mark_beginbuf = current->next;
2508 mark_beginx -= break_pos + 1 - indent_len;
2509 }
2510#endif
2511 null_at(&current->data, break_pos);
2512 current = current->next;
2513 } else if (display_len < fill && par_len > 1) {
2514 size_t next_line_len = strlen(current->next->data);
2515
2516 indent_len = quote_len +
2517 indent_length(current->next->data + quote_len);
2518 break_pos = break_line(current->next->data + indent_len,
2519 fill - display_len - 1, 0);
2520 if (break_pos == -1)
2521 /* We can't pull a word from the next line up to this one,
2522 * so just go on. */
2523 goto continue_loc;
2524
2525 /* If we haven't backed up the paragraph, do it now. */
2526 if (first_mod_line == NULL)
2527 first_mod_line = backup_lines(current, par_len, quote_len);
2528 current->data = (char *)nrealloc(current->data,
2529 line_len + break_pos + 2);
2530 current->data[line_len] = ' ';
2531 strncpy(current->data + line_len + 1,
2532 current->next->data + indent_len, break_pos);
2533 current->data[line_len + break_pos + 1] = '\0';
2534#ifndef NANO_SMALL
2535 if (mark_beginbuf == current->next) {
2536 if (mark_beginx < indent_len + break_pos) {
2537 mark_beginbuf = current;
2538 if (mark_beginx <= indent_len)
2539 mark_beginx = line_len + 1;
2540 else
2541 mark_beginx = line_len + 1 + mark_beginx - indent_len;
2542 } else
2543 mark_beginx -= break_pos + 1;
2544 }
2545#endif
2546 if (indent_len + break_pos == next_line_len) {
2547 line = current->next;
2548 unlink_node(line);
2549 delete_node(line);
2550 totlines--;
2551 totsize -= indent_len;
2552 current_y--;
2553 } else {
2554 memmove(current->next->data + indent_len,
2555 current->next->data + indent_len + break_pos + 1,
2556 next_line_len - break_pos - indent_len);
2557 null_at(&current->next->data,
2558 next_line_len - break_pos);
2559 current = current->next;
2560 }
2561 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002562 continue_loc:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002563 current = current->next;
2564 }
2565/* We are now done justifying the paragraph. There are cleanup things to
2566 * do, and we check for unjustify. */
2567
2568 /* totlines, totsize, and current_y have been maintained above. We
2569 * now set last_par_line to the new end of the paragraph, update
2570 * fileage, set current_x. Also, edit_refresh() needs the line
2571 * numbers to be right, so we renumber(). */
2572 last_par_line = current->prev;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002573 if (first_mod_line != NULL) {
2574 if (first_mod_line->prev == NULL)
2575 fileage = first_mod_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002576 renumber(first_mod_line);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002577 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002578
2579 if (current_y > editwinrows - 4)
2580 edit_update(current, CENTER);
2581 else
2582 edit_refresh();
2583
Chris Allegretta9149e612000-11-27 00:23:41 +00002584 statusbar(_("Can now UnJustify!"));
Chris Allegretta07798352000-11-27 22:58:23 +00002585 /* Change the shortcut list to display the unjustify code */
2586 shortcut_init(1);
2587 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002588 reset_cursor();
2589
Chris Allegretta6df90f52002-07-19 01:08:59 +00002590 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002591 * keystroke and return. */
Chris Allegretta5f071802001-05-06 02:34:31 +00002592
2593#ifndef DISABLE_MOUSE
2594#ifdef NCURSES_MOUSE_VERSION
Chris Allegretta6df90f52002-07-19 01:08:59 +00002595 /* If it was a mouse click, parse it with do_mouse() and it might
2596 * become the unjustify key. Else give it back to the input stream. */
2597 if ((i = wgetch(edit)) == KEY_MOUSE)
Chris Allegretta5f071802001-05-06 02:34:31 +00002598 do_mouse();
2599 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00002600 ungetch(i);
Chris Allegretta5f071802001-05-06 02:34:31 +00002601#endif
2602#endif
2603
Chris Allegretta6df90f52002-07-19 01:08:59 +00002604 if ((i = wgetch(edit)) != NANO_UNJUSTIFY_KEY) {
2605 ungetch(i);
2606 /* Did we back up anything at all? */
2607 if (cutbuffer != cutbuffer_save)
2608 free_filestruct(cutbuffer);
2609 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002610 } else {
Chris Allegretta9149e612000-11-27 00:23:41 +00002611 /* Else restore the justify we just did (ungrateful user!) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002612 current = current_save;
2613 current_x = current_x_save;
2614 current_y = current_y_save;
2615 edittop = edittop_save;
2616 editbot = editbot_save;
2617 if (first_mod_line != NULL) {
2618 filestruct *cutbottom = get_cutbottom();
Chris Allegrettad022eac2000-11-27 02:50:49 +00002619
Chris Allegretta6df90f52002-07-19 01:08:59 +00002620 /* Splice the cutbuffer back into the file. */
2621 cutbottom->next = last_par_line->next;
2622 cutbottom->next->prev = cutbottom;
2623 /* The line numbers after the end of the paragraph have
2624 * been changed, so we change them back. */
2625 renumber(cutbottom->next);
2626 if (first_mod_line->prev != NULL) {
2627 cutbuffer->prev = first_mod_line->prev;
2628 cutbuffer->prev->next = cutbuffer;
2629 } else
2630 fileage = cutbuffer;
2631 cutbuffer = NULL;
2632
2633 last_par_line->next = NULL;
2634 free_filestruct(first_mod_line);
2635
2636 /* Restore global variables from before justify */
2637 totsize = totsize_save;
2638 totlines = filebot->lineno;
2639#ifndef NANO_SMALL
2640 mark_beginbuf = mark_beginbuf_save;
2641 mark_beginx = mark_beginx_save;
2642#endif
2643 flags = flags_save;
2644 if (!ISSET(MODIFIED)) {
2645 titlebar(NULL);
2646 wrefresh(topwin);
2647 }
2648 }
2649 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002650 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002651 cutbuffer = cutbuffer_save;
2652 blank_statusbar_refresh();
2653 /* display shortcut list without UnCut */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002654 shortcut_init(0);
2655 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002656
Chris Allegretta6df90f52002-07-19 01:08:59 +00002657 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002658#endif
2659}
2660
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002661int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002662{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002663 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002664
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002665 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002666
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002667#ifdef ENABLE_MULTIBUFFER
2668 if (!close_open_file()) {
2669 display_main_list();
2670 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002671 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002672 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002673#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002674 finish(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00002675 }
2676
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002677 if (ISSET(TEMP_OPT)) {
2678 i = 1;
2679 } else {
2680 i = do_yesno(0, 0,
2681 _
2682 ("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2683 }
2684
2685#ifdef DEBUG
2686 dump_buffer(fileage);
2687#endif
2688
2689 if (i == 1) {
2690 if (do_writeout(filename, 1, 0) > 0) {
2691
2692#ifdef ENABLE_MULTIBUFFER
2693 if (!close_open_file()) {
2694 display_main_list();
2695 return 1;
2696 }
2697 else
2698#endif
2699 finish(0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002700 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002701 } else if (i == 0) {
2702
2703#ifdef ENABLE_MULTIBUFFER
2704 if (!close_open_file()) {
2705 display_main_list();
2706 return 1;
2707 }
2708 else
2709#endif
2710 finish(0);
2711 } else
2712 statusbar(_("Cancelled"));
2713
2714 display_main_list();
2715 return 1;
2716}
2717
2718void signal_init(void)
2719{
2720#ifdef _POSIX_VDISABLE
2721 struct termios term;
2722#endif
2723
2724 /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */
2725 memset(&act, 0, sizeof(struct sigaction));
2726 act.sa_handler = SIG_IGN;
2727 sigaction(SIGINT, &act, NULL);
2728
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002729 /* Trap SIGHUP and SIGTERM cuz we want to write the file out. */
2730 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002731 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002732 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002733
2734#ifndef NANO_SMALL
2735 act.sa_handler = handle_sigwinch;
2736 sigaction(SIGWINCH, &act, NULL);
2737#endif
2738
2739#ifdef _POSIX_VDISABLE
2740 tcgetattr(0, &term);
2741
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002742 /* Ignore ^S, much to Chris' chagrin */
Chris Allegrettae42df732002-10-15 00:27:55 +00002743 term.c_cc[VSTOP] = _POSIX_VDISABLE;
2744
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002745#ifdef VDSUSP
2746 term.c_cc[VDSUSP] = _POSIX_VDISABLE;
2747#endif /* VDSUSP */
2748
2749#endif /* _POSIX_VDISABLE */
2750
2751 if (!ISSET(SUSPEND)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002752 /* Insane! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002753#ifdef _POSIX_VDISABLE
2754 term.c_cc[VSUSP] = _POSIX_VDISABLE;
2755#else
2756 act.sa_handler = SIG_IGN;
2757 sigaction(SIGTSTP, &act, NULL);
2758#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002759 } else {
2760 /* If we don't do this, it seems other stuff interrupts the
2761 suspend handler! Try using nano with mutt without this
2762 line. */
2763 sigfillset(&act.sa_mask);
2764
2765 act.sa_handler = do_suspend;
2766 sigaction(SIGTSTP, &act, NULL);
2767
2768 act.sa_handler = do_cont;
2769 sigaction(SIGCONT, &act, NULL);
2770 }
2771
2772#ifdef _POSIX_VDISABLE
2773 tcsetattr(0, TCSANOW, &term);
2774#endif
2775}
2776
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002777/* Handler for SIGHUP and SIGTERM */
2778RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002779{
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002780 die(_("Received SIGHUP or SIGTERM"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002781}
2782
2783/* What do we do when we catch the suspend signal */
2784RETSIGTYPE do_suspend(int signal)
2785{
2786 endwin();
2787 printf("\n\n\n\n\nUse \"fg\" to return to nano\n");
2788 fflush(stdout);
2789
2790 /* Restore the terminal settings for the disabled keys */
2791 tcsetattr(0, TCSANOW, &oldterm);
2792
2793 /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but
2794 then we could be (and were) interrupted in the middle of the call.
2795 So we do it the mutt way instead */
2796 kill(0, SIGSTOP);
2797}
2798
2799/* Restore the suspend handler when we come back into the prog */
2800RETSIGTYPE do_cont(int signal)
2801{
2802 /* Now we just update the screen instead of having to reenable the
2803 SIGTSTP handler. */
2804
2805 doupdate();
2806 /* The Hurd seems to need this, otherwise a ^Y after a ^Z will
2807 start suspending again. */
2808 signal_init();
2809
2810#ifndef NANO_SMALL
2811 /* Perhaps the user resized the window while we slept. */
2812 handle_sigwinch(0);
2813#endif
2814}
2815
2816#ifndef NANO_SMALL
2817void handle_sigwinch(int s)
2818{
2819 const char *tty = ttyname(0);
2820 int fd;
2821 int result = 0;
2822 struct winsize win;
2823
2824 if (!tty)
2825 return;
2826 fd = open(tty, O_RDWR);
2827 if (fd == -1)
2828 return;
2829 result = ioctl(fd, TIOCGWINSZ, &win);
2830 close(fd);
2831 if (result == -1)
2832 return;
2833
2834 /* Could check whether the COLS or LINES changed, and return
2835 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2836 * variables, and in some cases ncurses has already updated them.
2837 * But not in all cases, argh. */
2838 COLS = win.ws_col;
2839 LINES = win.ws_row;
2840 if ((editwinrows = LINES - 5 + no_help()) < MIN_EDITOR_ROWS)
2841 die_too_small();
2842
2843#ifndef DISABLE_WRAPJUSTIFY
2844 fill = wrap_at;
2845 if (fill <= 0)
2846 fill += COLS;
2847 if (fill < MIN_FILL_LENGTH)
2848 die_too_small();
2849#endif
2850
2851 hblank = nrealloc(hblank, COLS + 1);
2852 memset(hblank, ' ', COLS);
2853 hblank[COLS] = '\0';
2854
2855#ifdef HAVE_RESIZETERM
2856 resizeterm(LINES, COLS);
2857#ifdef HAVE_WRESIZE
2858 if (wresize(topwin, 2, COLS) == ERR)
2859 die(_("Cannot resize top win"));
2860 if (mvwin(topwin, 0, 0) == ERR)
2861 die(_("Cannot move top win"));
2862 if (wresize(edit, editwinrows, COLS) == ERR)
2863 die(_("Cannot resize edit win"));
2864 if (mvwin(edit, 2, 0) == ERR)
2865 die(_("Cannot move edit win"));
2866 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
2867 die(_("Cannot resize bottom win"));
2868 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
2869 die(_("Cannot move bottom win"));
2870#endif /* HAVE_WRESIZE */
2871#endif /* HAVE_RESIZETERM */
2872
2873 fix_editbot();
2874
2875 if (current_y > editwinrows - 1)
2876 edit_update(editbot, CENTER);
2877 erase();
2878
2879 /* Do these b/c width may have changed... */
2880 refresh();
2881 titlebar(NULL);
2882 edit_refresh();
2883 display_main_list();
2884 blank_statusbar();
2885 total_refresh();
2886
2887 /* Turn cursor back on for sure */
2888 curs_set(1);
2889
2890 /* Jump back to main loop */
2891 siglongjmp(jmpbuf, 1);
2892}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002893#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002894
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002895/* If the NumLock key has made the keypad go awry, print an error
2896 message; hopefully we can address it later. */
2897void print_numlock_warning(void)
2898{
2899 static int didmsg = 0;
2900 if (!didmsg) {
2901 statusbar(_
2902 ("NumLock glitch detected. Keypad will malfunction with NumLock off"));
2903 didmsg = 1;
2904 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002905}
2906
Chris Allegrettadab017e2002-04-23 10:56:06 +00002907#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002908void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002909{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002910 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002911
Chris Allegretta658399a2001-06-14 02:54:22 +00002912 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002913 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002914
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002915 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002916 case TOGGLE_PICOMODE_KEY:
Chris Allegretta07798352000-11-27 22:58:23 +00002917 shortcut_init(0);
Chris Allegrettac1049ac2001-08-17 00:03:46 +00002918 SET(CLEAR_BACKUPSTRING);
Chris Allegretta756f2202000-09-01 13:32:47 +00002919 display_main_list();
2920 break;
2921 case TOGGLE_SUSPEND_KEY:
2922 signal_init();
2923 break;
2924 case TOGGLE_MOUSE_KEY:
2925 mouse_init();
2926 break;
2927 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00002928 wclear(bottomwin);
2929 wrefresh(bottomwin);
2930 window_init();
Chris Allegrettaaffeda82000-12-18 04:03:48 +00002931 fix_editbot();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002932 edit_refresh();
2933 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002934 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002935 case TOGGLE_DOS_KEY:
2936 UNSET(MAC_FILE);
2937 break;
2938 case TOGGLE_MAC_KEY:
2939 UNSET(DOS_FILE);
2940 break;
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002941 case TOGGLE_SYNTAX_KEY:
2942 edit_refresh();
2943 break;
Chris Allegretta756f2202000-09-01 13:32:47 +00002944 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002945
Chris Allegretta6df90f52002-07-19 01:08:59 +00002946 /* We are assuming here that shortcut_init() above didn't free and
2947 * reallocate the toggles. */
2948 enabled = ISSET(which->flag);
2949 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2950 enabled = !enabled;
2951 statusbar("%s %s", which->desc,
2952 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002953}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002954#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002955
Chris Allegretta1748cd12001-01-13 17:22:54 +00002956/* This function returns the correct keystroke, given the A,B,C or D
2957 input key. This is a common sequence of many terms which send
2958 Esc-O-[A-D] or Esc-[-[A-D]. */
2959int ABCD(int input)
2960{
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002961 switch (input) {
2962 case 'A':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002963 case 'a':
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002964 return (KEY_UP);
2965 case 'B':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002966 case 'b':
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002967 return (KEY_DOWN);
2968 case 'C':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002969 case 'c':
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002970 return (KEY_RIGHT);
2971 case 'D':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002972 case 'd':
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002973 return (KEY_LEFT);
2974 default:
2975 return 0;
Chris Allegretta1748cd12001-01-13 17:22:54 +00002976 }
2977}
2978
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002979int main(int argc, char *argv[])
2980{
2981 int optchr;
2982 int kbinput; /* Input from keyboard */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00002983 int startline = 0; /* Line to try and start at */
Chris Allegretta08020882001-01-29 23:37:54 +00002984 int keyhandled; /* Have we handled the keystroke yet? */
Chris Allegretta9caa1932002-02-15 20:08:05 +00002985 int modify_control_seq;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002986 const char *argv0;
2987 const shortcut *s;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00002988#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00002989 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00002990#endif
Chris Allegretta0357c4d2001-09-19 02:59:25 +00002991
Chris Allegretta9b4055c2002-03-29 16:00:59 +00002992#ifdef _POSIX_VDISABLE
2993 struct termios term;
2994#endif
2995
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002996#ifdef HAVE_GETOPT_LONG
2997 int option_index = 0;
2998 struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002999 {"help", 0, 0, 'h'},
3000#ifdef ENABLE_MULTIBUFFER
3001 {"multibuffer", 0, 0, 'F'},
3002#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003003#ifdef ENABLE_NANORC
3004 {"ignorercfiles", 0, 0, 'I'},
3005#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003006 {"keypad", 0, 0, 'K'},
3007#ifndef DISABLE_JUSTIFY
3008 {"quotestr", 1, 0, 'Q'},
3009#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003010#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003011 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003012#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003013 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003014 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003015#ifdef ENABLE_COLOR
3016 {"syntax", 1, 0, 'Y'},
3017#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003018 {"const", 0, 0, 'c'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003019 {"nofollow", 0, 0, 'l'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003020 {"mouse", 0, 0, 'm'},
Chris Allegrettae1f14522001-09-19 03:19:43 +00003021#ifndef DISABLE_OPERATINGDIR
3022 {"operatingdir", 1, 0, 'o'},
3023#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003024 {"pico", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003025#ifndef DISABLE_WRAPJUSTIFY
3026 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003027#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003028#ifndef DISABLE_SPELLER
3029 {"speller", 1, 0, 's'},
3030#endif
3031 {"tempfile", 0, 0, 't'},
3032 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003033#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003034 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003035#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003036 {"nohelp", 0, 0, 'x'},
3037 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003038#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003039 {"backup", 0, 0, 'B'},
3040 {"dos", 0, 0, 'D'},
3041 {"mac", 0, 0, 'M'},
3042 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003043 {"smooth", 0, 0, 'S'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003044 {"autoindent", 0, 0, 'i'},
3045 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003046#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003047 {0, 0, 0, 0}
3048 };
3049#endif
3050
3051 /* Flag inits... */
3052 SET(FOLLOW_SYMLINKS);
3053
3054#ifndef NANO_SMALL
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003055#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003056 setlocale(LC_ALL, "");
3057 bindtextdomain(PACKAGE, LOCALEDIR);
3058 textdomain(PACKAGE);
3059#endif
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003060#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003061
Chris Allegretta8d8e0122001-04-18 04:28:54 +00003062#ifdef ENABLE_NANORC
Chris Allegretta1c5c3382002-07-23 00:33:07 +00003063 {
3064 /* scan through the options and handle -I/--ignorercfiles
3065 first, so that it's handled before we call do_rcfile() and
3066 read the other options; don't use getopt()/getopt_long()
3067 here, because there's no way to reset it properly
3068 afterward */
3069 int i;
3070 for (i = 1; i < argc; i++) {
3071 if (!strcmp(argv[i], "--"))
3072 break;
3073 else if (!strcmp(argv[i], "-I"))
3074 SET(NO_RCFILE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003075#ifdef HAVE_GETOPT_LONG
Chris Allegretta1c5c3382002-07-23 00:33:07 +00003076 else if (!strcmp(argv[i], "--ignorercfiles"))
3077 SET(NO_RCFILE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00003078#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003079 }
3080 }
Chris Allegretta1c5c3382002-07-23 00:33:07 +00003081 if (!ISSET(NO_RCFILE))
3082 do_rcfile();
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003083#else
3084#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
3085 /* if we don't have rcfile support, we're root, and
3086 --disable-wrapping-as-root is used, turn wrapping off */
3087 if (geteuid() == 0)
3088 SET(NO_WRAP);
3089#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003090#endif /* ENABLE_NANORC */
3091
3092#ifdef HAVE_GETOPT_LONG
3093 while ((optchr = getopt_long(argc, argv, "h?BDFIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz",
3094 long_options, &option_index)) != EOF) {
3095#else
3096 while ((optchr =
3097 getopt(argc, argv, "h?BDFIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz")) != EOF) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003098#endif
3099
3100 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003101
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003102 case 'h':
3103 case '?':
3104 usage();
3105 exit(0);
3106 case 'a':
3107 case 'b':
3108 case 'e':
3109 case 'f':
3110 case 'g':
3111 case 'j':
3112 /* Pico compatibility flags */
3113 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003114#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003115 case 'B':
3116 SET(BACKUP_FILE);
3117 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003118 case 'D':
3119 SET(DOS_FILE);
3120 break;
3121#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003122#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003123 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003124 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003125 break;
3126#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003127#ifdef ENABLE_NANORC
Chris Allegretta6df90f52002-07-19 01:08:59 +00003128 case 'I':
3129 break;
3130#endif
Chris Allegretta48bd3782002-01-03 21:26:34 +00003131 case 'K':
3132 SET(ALT_KEYPAD);
3133 break;
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003134#ifndef NANO_SMALL
3135 case 'M':
3136 SET(MAC_FILE);
3137 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003138 case 'N':
3139 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003140 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003141#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003142 case 'Q':
3143#ifndef DISABLE_JUSTIFY
3144 quotestr = optarg;
3145 break;
3146#else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003147 usage();
3148 exit(1);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003149#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003150#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003151 case 'R':
3152 SET(USE_REGEXP);
3153 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003154#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003155#ifndef NANO_SMALL
3156 case 'S':
3157 SET(SMOOTHSCROLL);
3158 break;
3159#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003160 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003161 {
3162 int i;
3163 char *first_error;
3164
3165 /* Using strtol instead of atoi lets us accept 0 while
3166 * checking other errors. */
3167 i = (int)strtol(optarg, &first_error, 10);
3168 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0') {
3169 usage();
3170 exit(1);
3171 } else
3172 tabsize = i;
3173 if (tabsize <= 0) {
3174 fprintf(stderr, _("Tab size is too small for nano...\n"));
3175 exit(1);
3176 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003177 }
3178 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003179 case 'V':
3180 version();
3181 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003182#ifdef ENABLE_COLOR
3183 case 'Y':
3184 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3185 break;
3186#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003187 case 'c':
3188 SET(CONSTUPDATE);
3189 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003190#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003191 case 'i':
3192 SET(AUTOINDENT);
3193 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003194 case 'k':
3195 SET(CUT_TO_END);
3196 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003197#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003198 case 'l':
3199 UNSET(FOLLOW_SYMLINKS);
3200 break;
3201 case 'm':
3202 SET(USE_MOUSE);
3203 break;
Chris Allegrettae1f14522001-09-19 03:19:43 +00003204#ifndef DISABLE_OPERATINGDIR
3205 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003206 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003207 break;
3208#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003209 case 'p':
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +00003210 SET(PICO_MODE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003211 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003212#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003213 case 'r':
3214 {
3215 int i;
3216 char *first_error;
3217
3218 /* Using strtol instead of atoi lets us accept 0 while
3219 * checking other errors. */
3220 i = (int)strtol(optarg, &first_error, 10);
3221 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0') {
3222 usage();
3223 exit(1);
3224 } else
3225 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003226 }
3227 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003228#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003229#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003230 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003231 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003232 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003233#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003234 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003235 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003236 break;
3237 case 'v':
3238 SET(VIEW_MODE);
3239 break;
3240 case 'w':
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00003241#ifdef DISABLE_WRAPPING
3242 usage();
3243 exit(0);
3244#else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003245 SET(NO_WRAP);
3246 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003247#endif /* DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003248 case 'x':
3249 SET(NO_HELP);
3250 break;
3251 case 'z':
3252 SET(SUSPEND);
3253 break;
3254 default:
3255 usage();
Chris Allegretta4da1fc62000-06-21 03:00:43 +00003256 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003257 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003258 }
3259
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003260#ifndef DISABLE_OPERATINGDIR
3261 /* Set up the operating directory. This entails chdir()ing there, so
3262 that file reads and writes will be based there. */
3263 init_operating_dir();
3264#endif
3265
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003266 /* Clear the filename we'll be using */
3267 filename = charalloc(1);
3268 filename[0] = '\0';
3269
3270 /* See if we were invoked with the name "pico" */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003271 argv0 = strrchr(argv[0], '/');
3272 if ((argv0 && strstr(argv0, "pico"))
3273 || (!argv0 && strstr(argv[0], "pico")))
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +00003274 SET(PICO_MODE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003275
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003276 /* See if there's a non-option in argv (first non-option is the
3277 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003278 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003279 /* Look for the +line flag... */
3280 if (argv[optind][0] == '+') {
3281 startline = atoi(&argv[optind][1]);
3282 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003283 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003284 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003285 } else
3286 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003287 }
3288
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003289 /* First back up the old settings so they can be restored, duh */
3290 tcgetattr(0, &oldterm);
3291
3292#ifdef _POSIX_VDISABLE
3293 term = oldterm;
3294 term.c_cc[VINTR] = _POSIX_VDISABLE;
3295 term.c_cc[VQUIT] = _POSIX_VDISABLE;
3296 term.c_lflag &= ~IEXTEN;
3297 tcsetattr(0, TCSANOW, &term);
3298#endif
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003299
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003300 /* now ncurses init stuff... */
3301 initscr();
3302 savetty();
3303 nonl();
3304 cbreak();
3305 noecho();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003306
3307 /* Set up some global variables */
Chris Allegretta56214c62001-09-27 02:46:53 +00003308 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003309 shortcut_init(0);
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003310 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003311
3312#ifdef DEBUG
3313 fprintf(stderr, _("Main: set up windows\n"));
3314#endif
3315
Chris Allegretta2a42af12000-09-12 23:02:49 +00003316 window_init();
Chris Allegretta756f2202000-09-01 13:32:47 +00003317 mouse_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003318
Chris Allegretta48bd3782002-01-03 21:26:34 +00003319 if (!ISSET(ALT_KEYPAD)) {
3320 keypad(edit, TRUE);
3321 keypad(bottomwin, TRUE);
3322 }
3323
Chris Allegretta08893e02001-11-29 02:42:27 +00003324#ifdef ENABLE_COLOR
3325 do_colorinit();
Chris Allegretta08893e02001-11-29 02:42:27 +00003326#endif /* ENABLE_COLOR */
3327
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003328#ifdef DEBUG
3329 fprintf(stderr, _("Main: bottom win\n"));
3330#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003331 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003332 display_main_list();
3333
3334#ifdef DEBUG
3335 fprintf(stderr, _("Main: open file\n"));
3336#endif
3337
Chris Allegretta31c76662000-11-21 06:20:20 +00003338 /* Now we check to see if argv[optind] is non-null to determine if
3339 we're dealing with a new file or not, not argc == 1... */
3340 if (argv[optind] == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003341 new_file();
3342 else
3343 open_file(filename, 0, 0);
3344
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003345 titlebar(NULL);
3346
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003347 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003348 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003349 else
Chris Allegretta234a34d2000-07-29 04:33:38 +00003350 edit_update(fileage, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003351
Chris Allegretta08020882001-01-29 23:37:54 +00003352 /* return here after a sigwinch */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003353 sigsetjmp(jmpbuf, 1);
Chris Allegretta08020882001-01-29 23:37:54 +00003354
3355 /* Fix clobber-age */
3356 kbinput = 0;
3357 keyhandled = 0;
3358 modify_control_seq = 0;
3359
Robert Siemborski6967eec2000-07-08 14:23:32 +00003360 edit_refresh();
3361 reset_cursor();
3362
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003363 while (1) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003364
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003365#if !defined(DISABLE_BROWSER) || !defined(DISABLE_MOUSE) || !defined(DISABLE_HELP)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003366 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003367#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003368
Chris Allegretta9239d742000-09-06 15:19:18 +00003369#ifndef _POSIX_VDISABLE
3370 /* We're going to have to do it the old way, i.e. on cygwin */
3371 raw();
3372#endif
3373
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003374 kbinput = wgetch(edit);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003375#ifdef DEBUG
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003376 fprintf(stderr, _("AHA! %c (%d)\n"), kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003377#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003378 if (kbinput == 27) { /* Grab Alt-key stuff first */
3379 switch (kbinput = wgetch(edit)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003380 /* Alt-O, suddenly very important ;) */
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003381 case 'O':
Chris Allegretta16e41682000-09-11 22:33:54 +00003382 kbinput = wgetch(edit);
Chris Allegretta316e4d92001-04-28 16:31:19 +00003383 if ((kbinput <= 'D' && kbinput >= 'A') ||
3384 (kbinput <= 'd' && kbinput >= 'a'))
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003385 kbinput = ABCD(kbinput);
Chris Allegretta201d9bf2001-01-14 03:17:53 +00003386 else if (kbinput <= 'z' && kbinput >= 'j')
3387 print_numlock_warning();
3388 else if (kbinput <= 'S' && kbinput >= 'P')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003389 kbinput = KEY_F(kbinput - 79);
Chris Allegretta16e41682000-09-11 22:33:54 +00003390#ifdef DEBUG
3391 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003392 fprintf(stderr, _("I got Alt-O-%c! (%d)\n"),
3393 kbinput, kbinput);
3394 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003395 }
3396#endif
3397 break;
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003398 case 27:
3399 /* If we get Alt-Alt, the next keystroke should be the same as a
3400 control sequence */
3401 modify_control_seq = 1;
3402 keyhandled = 1;
3403 break;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003404 case '[':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003405 switch (kbinput = wgetch(edit)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003406 case '1': /* Alt-[-1-[0-5,7-9] = F1-F8 in X at least */
Chris Allegretta16e41682000-09-11 22:33:54 +00003407 kbinput = wgetch(edit);
3408 if (kbinput >= '1' && kbinput <= '5') {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003409 kbinput = KEY_F(kbinput - 48);
3410 wgetch(edit);
3411 } else if (kbinput >= '7' && kbinput <= '9') {
3412 kbinput = KEY_F(kbinput - 49);
3413 wgetch(edit);
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003414 } else if (kbinput == '~')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003415 kbinput = KEY_HOME;
Chris Allegretta16e41682000-09-11 22:33:54 +00003416#ifdef DEBUG
3417 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003418 fprintf(stderr, _("I got Alt-[-1-%c! (%d)\n"),
3419 kbinput, kbinput);
3420 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003421 }
3422#endif
Chris Allegretta16e41682000-09-11 22:33:54 +00003423 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003424 case '2': /* Alt-[-2-[0,1,3,4] = F9-F12 in many terms */
Chris Allegretta16e41682000-09-11 22:33:54 +00003425 kbinput = wgetch(edit);
Chris Allegretta16e41682000-09-11 22:33:54 +00003426 switch (kbinput) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003427 case '0':
3428 kbinput = KEY_F(9);
3429 wgetch(edit);
3430 break;
3431 case '1':
3432 kbinput = KEY_F(10);
3433 wgetch(edit);
3434 break;
3435 case '3':
3436 kbinput = KEY_F(11);
3437 wgetch(edit);
3438 break;
3439 case '4':
3440 kbinput = KEY_F(12);
3441 wgetch(edit);
3442 break;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003443 case '~':
3444 goto do_insertkey;
Chris Allegretta16e41682000-09-11 22:33:54 +00003445#ifdef DEBUG
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003446 default:
3447 fprintf(stderr, _("I got Alt-[-2-%c! (%d)\n"),
3448 kbinput, kbinput);
3449 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003450#endif
Chris Allegretta16e41682000-09-11 22:33:54 +00003451 }
3452 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003453 case '3': /* Alt-[-3 = Delete? */
Chris Allegretta16e41682000-09-11 22:33:54 +00003454 kbinput = NANO_DELETE_KEY;
3455 wgetch(edit);
3456 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003457 case '4': /* Alt-[-4 = End? */
Chris Allegretta16e41682000-09-11 22:33:54 +00003458 kbinput = NANO_END_KEY;
3459 wgetch(edit);
3460 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003461 case '5': /* Alt-[-5 = Page Up */
Chris Allegretta16e41682000-09-11 22:33:54 +00003462 kbinput = KEY_PPAGE;
3463 wgetch(edit);
3464 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003465 case 'V': /* Alt-[-V = Page Up in Hurd Console */
Chris Allegretta7bf72742001-10-28 04:29:55 +00003466 case 'I': /* Alt-[-I = Page Up - FreeBSD Console */
3467 kbinput = KEY_PPAGE;
3468 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003469 case '6': /* Alt-[-6 = Page Down */
Chris Allegretta16e41682000-09-11 22:33:54 +00003470 kbinput = KEY_NPAGE;
3471 wgetch(edit);
3472 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003473 case 'U': /* Alt-[-U = Page Down in Hurd Console */
Chris Allegretta7bf72742001-10-28 04:29:55 +00003474 case 'G': /* Alt-[-G = Page Down - FreeBSD Console */
3475 kbinput = KEY_NPAGE;
3476 break;
Chris Allegrettab26ecb52001-07-04 16:27:05 +00003477 case '7':
3478 kbinput = KEY_HOME;
3479 wgetch(edit);
3480 break;
3481 case '8':
3482 kbinput = KEY_END;
3483 wgetch(edit);
3484 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003485 case '9': /* Alt-[-9 = Delete in Hurd Console */
3486 kbinput = KEY_DC;
3487 break;
Chris Allegretta32da4562002-01-02 15:12:21 +00003488 case '@': /* Alt-[-@ = Insert in Hurd Console */
3489 case 'L': /* Alt-[-L = Insert - FreeBSD Console */
3490 goto do_insertkey;
3491 case '[': /* Alt-[-[-[A-E], F1-F5 in Linux console */
Chris Allegretta16e41682000-09-11 22:33:54 +00003492 kbinput = wgetch(edit);
Chris Allegrettab26ecb52001-07-04 16:27:05 +00003493 if (kbinput >= 'A' && kbinput <= 'E')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003494 kbinput = KEY_F(kbinput - 64);
Chris Allegretta16e41682000-09-11 22:33:54 +00003495 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003496 case 'A':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003497 case 'B':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003498 case 'C':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003499 case 'D':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003500 case 'a':
3501 case 'b':
3502 case 'c':
3503 case 'd':
Chris Allegretta1748cd12001-01-13 17:22:54 +00003504 kbinput = ABCD(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003505 break;
3506 case 'H':
3507 kbinput = KEY_HOME;
3508 break;
3509 case 'F':
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003510 case 'Y': /* End Key in Hurd Console */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003511 kbinput = KEY_END;
3512 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003513 default:
3514#ifdef DEBUG
3515 fprintf(stderr, _("I got Alt-[-%c! (%d)\n"),
3516 kbinput, kbinput);
3517#endif
3518 break;
3519 }
3520 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003521
Chris Allegretta355fbe52001-07-14 19:32:47 +00003522#ifdef ENABLE_MULTIBUFFER
Chris Allegretta819e3db2001-07-11 02:37:19 +00003523 case NANO_OPENPREV_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003524 case NANO_OPENPREV_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003525 open_prevfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003526 keyhandled = 1;
3527 break;
3528 case NANO_OPENNEXT_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003529 case NANO_OPENNEXT_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003530 open_nextfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003531 keyhandled = 1;
3532 break;
Chris Allegretta9cf9e062001-07-11 12:06:13 +00003533#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003534 default:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003535 /* Check for the altkey defs.... */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003536 for (s = main_list; s != NULL; s = s->next)
3537 if (kbinput == s->altval ||
Chris Allegretta6232d662002-05-12 19:52:15 +00003538 kbinput == s->altval - 32) {
3539 if (ISSET(VIEW_MODE) && !s->viewok)
3540 print_view_warning();
3541 else
3542 s->func();
3543 keyhandled = 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003544 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003545 }
Chris Allegretta756f2202000-09-01 13:32:47 +00003546#ifndef NANO_SMALL
3547 /* And for toggle switches */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003548 for (t = toggles; t != NULL && !keyhandled; t = t->next)
3549 if (kbinput == t->val ||
3550 (t->val > 'a' &&
3551 kbinput == t->val - 32)) {
3552 do_toggle(t);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003553 keyhandled = 1;
3554 break;
Chris Allegretta756f2202000-09-01 13:32:47 +00003555 }
3556#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003557#ifdef DEBUG
3558 fprintf(stderr, _("I got Alt-%c! (%d)\n"), kbinput,
3559 kbinput);
3560#endif
3561 break;
3562 }
3563 }
Chris Allegrettacf287c82002-07-20 13:57:41 +00003564 /* If modify_control_seq is set, we received an Alt-Alt
3565 sequence before this, so we make this key a control sequence
3566 by subtracting 32, 64, or 96, depending on its value. */
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003567 if (!keyhandled && modify_control_seq) {
Chris Allegrettacf287c82002-07-20 13:57:41 +00003568 if (kbinput == ' ')
3569 kbinput -= 32;
3570 else if (kbinput >= 'A' && kbinput < 'a')
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003571 kbinput -= 64;
3572 else if (kbinput >= 'a' && kbinput <= 'z')
3573 kbinput -= 96;
3574
3575 modify_control_seq = 0;
3576 }
3577
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003578 /* Look through the main shortcut list to see if we've hit a
3579 shortcut key */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003580
Chris Allegrettaf5de33a2002-02-27 04:14:16 +00003581#if !defined(DISABLE_BROWSER) || !defined(DISABLE_MOUSE) || !defined (DISABLE_HELP)
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003582 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
Chris Allegrettaf5de33a2002-02-27 04:14:16 +00003583#else
3584 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
3585#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003586 if (kbinput == s->val ||
3587 (s->misc1 && kbinput == s->misc1) ||
3588 (s->misc2 && kbinput == s->misc2)) {
3589 if (ISSET(VIEW_MODE) && !s->viewok)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003590 print_view_warning();
3591 else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003592 s->func();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003593 keyhandled = 1;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003594 /* rarely, the value of s can change after s->func(),
3595 leading to problems; get around this by breaking out
3596 explicitly once we successfully handle a shortcut */
3597 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003598 }
3599 }
Chris Allegrettae42df732002-10-15 00:27:55 +00003600
3601#ifdef _POSIX_VDISABLE
3602 /* Don't even think about changing this string */
3603 if (kbinput == 19)
3604 statusbar(_("XOFF ignored, mumble mumble."));
3605#endif
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003606 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3607 Control-S and Control-Q */
Chris Allegretta9239d742000-09-06 15:19:18 +00003608 if (kbinput == 17 || kbinput == 19)
3609 keyhandled = 1;
3610
Chris Allegretta9caa1932002-02-15 20:08:05 +00003611 /* Catch ^Z by hand when triggered also
3612 407 == ^Z in Linux console when keypad() is used? */
3613 if (kbinput == 26 || kbinput == 407) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003614 if (ISSET(SUSPEND))
3615 do_suspend(0);
3616 keyhandled = 1;
3617 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003618
Chris Allegretta1c27d3e2001-10-02 02:56:45 +00003619#ifndef USE_SLANG
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003620 /* Hack, make insert key do something useful, like insert file */
3621 if (kbinput == KEY_IC) {
Chris Allegretta1c27d3e2001-10-02 02:56:45 +00003622#else
3623 if (0) {
3624#endif
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003625 do_insertkey:
3626
3627#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +00003628 /* do_insertfile_void() contains the logic needed to
3629 handle view mode with the view mode/multibuffer
3630 exception, so use it here */
3631 do_insertfile_void();
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003632#else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003633 if (!ISSET(VIEW_MODE))
3634 do_insertfile_void();
3635 else
3636 print_view_warning();
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003637#endif
3638
Chris Allegretta1c27d3e2001-10-02 02:56:45 +00003639 keyhandled = 1;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003640 }
3641
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003642 /* Last gasp, stuff that's not in the main lists */
3643 if (!keyhandled)
3644 switch (kbinput) {
Chris Allegretta84de5522001-04-12 14:51:48 +00003645#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003646#ifdef NCURSES_MOUSE_VERSION
3647 case KEY_MOUSE:
3648 do_mouse();
3649 break;
3650#endif
3651#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003652
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003653 case 0: /* Erg */
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003654 case -1: /* Stuff that we don't want to do squat */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003655 case 410: /* Must ignore this, it gets sent when we resize */
Chris Allegrettab3655b42001-10-22 03:15:31 +00003656 case 29: /* Ctrl-] */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003657#ifdef PDCURSES
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003658 case 541: /* ???? */
3659 case 542: /* Control and alt in Windows *shrug* */
Chris Allegretta72623582000-11-29 23:43:28 +00003660 case 543: /* Right ctrl key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003661 case 544:
Chris Allegretta72623582000-11-29 23:43:28 +00003662 case 545: /* Right alt key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003663#endif
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003664
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003665 break;
3666 default:
3667#ifdef DEBUG
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003668 fprintf(stderr, _("I got %c (%d)!\n"), kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003669#endif
3670 /* We no longer stop unhandled sequences so that people with
3671 odd character sets can type... */
3672
3673 if (ISSET(VIEW_MODE)) {
3674 print_view_warning();
3675 break;
3676 }
3677 do_char(kbinput);
3678 }
Chris Allegretta7fdbd052001-10-02 00:55:38 +00003679 if (ISSET(DISABLE_CURPOS))
3680 UNSET(DISABLE_CURPOS);
3681 else if (ISSET(CONSTUPDATE))
Chris Allegretta2084acc2001-11-29 03:43:08 +00003682 do_cursorpos(1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003683
3684 reset_cursor();
3685 wrefresh(edit);
3686 keyhandled = 0;
3687 }
3688
3689 getchar();
3690 finish(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003691}