blob: 88928e178dfb3b9edd51099769adc6de2bea9c85 [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 Allegretta6232d662002-05-12 19:52:15 +000045#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000046#include <libintl.h>
47#define _(string) gettext(string)
48#else
49#define _(string) (string)
50#endif
51
52#ifdef HAVE_TERMIOS_H
53#include <termios.h>
54#endif
55
56#ifdef HAVE_TERMIO_H
57#include <termio.h>
58#endif
59
60#ifdef HAVE_GETOPT_H
61#include <getopt.h>
62#endif
63
Chris Allegretta6fe61492001-05-21 12:56:25 +000064#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +000065static int fill = 0; /* Fill - where to wrap lines, basically */
Chris Allegretta6fe61492001-05-21 12:56:25 +000066#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000067
Chris Allegretta6df90f52002-07-19 01:08:59 +000068static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000069static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000070
Chris Allegretta08020882001-01-29 23:37:54 +000071static sigjmp_buf jmpbuf; /* Used to return to mainloop after SIGWINCH */
72
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000073/* What we do when we're all set to exit */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +000074RETSIGTYPE finish(int sigage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000075{
Chris Allegrettac08f50d2001-01-06 18:12:43 +000076 keypad(edit, TRUE);
77 keypad(bottomwin, TRUE);
78
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000079 if (!ISSET(NO_HELP)) {
80 mvwaddstr(bottomwin, 1, 0, hblank);
81 mvwaddstr(bottomwin, 2, 0, hblank);
Chris Allegretta4da1fc62000-06-21 03:00:43 +000082 } else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000083 mvwaddstr(bottomwin, 0, 0, hblank);
Chris Allegretta6b58acd2001-04-12 03:01:53 +000084
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000085 wrefresh(bottomwin);
86 endwin();
87
88 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000089 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000090
Chris Allegretta6232d662002-05-12 19:52:15 +000091#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000092 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +000093#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000094
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000095 exit(sigage);
96}
97
98/* Die (gracefully?) */
Chris Allegretta6df90f52002-07-19 01:08:59 +000099void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000100{
101 va_list ap;
102
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000103 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000104 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000105
106 clear();
107 refresh();
108 resetty();
109 endwin();
110
Chris Allegretta6df90f52002-07-19 01:08:59 +0000111 va_start(ap, msg);
112 vfprintf(stderr, msg, ap);
113 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000114
Chris Allegretta32da4562002-01-02 15:12:21 +0000115 /* save the currently loaded file if it's been modified */
116 if (ISSET(MODIFIED))
117 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000118
Chris Allegretta355fbe52001-07-14 19:32:47 +0000119#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000120 /* then save all of the other modified loaded files, if any */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000121 if (open_files) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000122 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000123
124 tmp = open_files;
125
126 while (open_files->prev)
127 open_files = open_files->prev;
128
129 while (open_files->next) {
130
131 /* if we already saved the file above (i. e. if it was the
132 currently loaded file), don't save it again */
133 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000134 /* make sure open_files->fileage and fileage, and
135 open_files->filebot and filebot, are in sync; they
136 might not be if lines have been cut from the top or
137 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000138 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000139 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000140 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000141 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000142 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000143 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000144 open_files = open_files->next;
145 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000146 }
147#endif
148
Chris Allegretta6df90f52002-07-19 01:08:59 +0000149 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000150}
151
Chris Allegretta6df90f52002-07-19 01:08:59 +0000152void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000153{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000154 char *ret;
Chris Allegretta48b06702002-02-22 04:30:50 +0000155 int i = -1;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000156
Chris Allegretta6df90f52002-07-19 01:08:59 +0000157 /* If we can't save, we have REAL bad problems, but we might as well
158 TRY. */
159 if (die_filename[0] == '\0')
160 ret = get_next_filename("nano.save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000161 else {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000162 char *buf = charalloc(strlen(die_filename) + 6);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000163
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000164 strcpy(buf, die_filename);
165 strcat(buf, ".save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000166 ret = get_next_filename(buf);
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000167 free(buf);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000168 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000169 if (ret[0] != '\0')
170 i = write_file(ret, 1, 0, 0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000171
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000172 if (i != -1)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000173 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000174 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000175 fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000176
177 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000178}
179
Chris Allegrettae61e8302001-01-14 05:18:27 +0000180/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000181 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000182void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000183{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000184 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000185}
186
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000187void print_view_warning(void)
188{
189 statusbar(_("Key illegal in VIEW mode"));
190}
191
Chris Allegretta56214c62001-09-27 02:46:53 +0000192/* Initialize global variables - no better way for now. If
Chris Allegretta6df90f52002-07-19 01:08:59 +0000193 * save_cutbuffer is nonzero, don't set cutbuffer to NULL. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000194void global_init(int save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000195{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000196 current_x = 0;
197 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000198
199 if ((editwinrows = LINES - 5 + no_help()) < MIN_EDITOR_ROWS)
200 die_too_small();
201
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000202 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000203 if (!save_cutbuffer)
204 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000205 current = NULL;
206 edittop = NULL;
207 editbot = NULL;
208 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000209 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000210 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000211
Chris Allegretta6fe61492001-05-21 12:56:25 +0000212#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000213 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000214 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000215 fill += COLS;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000216 if (fill < MIN_FILL_LENGTH)
217 die_too_small();
Chris Allegretta6fe61492001-05-21 12:56:25 +0000218#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000219
Chris Allegretta88b09152001-05-17 11:35:43 +0000220 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000221 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000222 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000223}
224
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000225void window_init(void)
226{
227 if ((editwinrows = LINES - 5 + no_help()) < MIN_EDITOR_ROWS)
228 die_too_small();
229
230 /* Set up the main text window */
231 edit = newwin(editwinrows, COLS, 2, 0);
232
233 /* And the other windows */
234 topwin = newwin(2, COLS, 0, 0);
235 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
236
237#ifdef PDCURSES
238 /* Oops, I guess we need this again.
239 Moved here so the keypad still works after a Meta-X, for example */
240 keypad(edit, TRUE);
241 keypad(bottomwin, TRUE);
242#endif
243}
244
245void mouse_init(void)
246{
247#ifndef DISABLE_MOUSE
248#ifdef NCURSES_MOUSE_VERSION
249 if (ISSET(USE_MOUSE)) {
250 keypad_on(edit, 1);
251 keypad_on(bottomwin, 1);
252
253 mousemask(BUTTON1_RELEASED, NULL);
254 mouseinterval(50);
255 } else
256 mousemask(0, NULL);
257#endif
258#endif
259}
260
261#ifndef DISABLE_HELP
262/* This function allocates help_text, and stores the help string in it.
263 * help_text should be NULL initially. */
264void help_init(void)
265{
266 size_t allocsize = 1; /* space needed for help_text */
267 char *ptr = NULL;
268#ifndef NANO_SMALL
269 const toggle *t;
270#endif
271 const shortcut *s;
272
273 /* First set up the initial help text for the current function */
274 if (currshortcut == whereis_list || currshortcut == replace_list
275 || currshortcut == replace_list_2)
276 ptr = _("Search Command Help Text\n\n "
277 "Enter the words or characters you would like to search "
278 "for, then hit enter. If there is a match for the text you "
279 "entered, the screen will be updated to the location of the "
280 "nearest match for the search string.\n\n "
281 "If using Pico Mode via the -p or --pico flags, the "
282 "Meta-P toggle, or a nanorc file, the previous search "
283 "string will be shown in brackets after the Search: prompt. "
284 "Hitting Enter without entering any text will perform the "
285 "previous search. Otherwise, the previous string will be "
286 "placed before the cursor, and can be edited or deleted "
287 "before hitting enter.\n\n The following function keys are "
288 "available in Search mode:\n\n");
289 else if (currshortcut == goto_list)
290 ptr = _("Go To Line Help Text\n\n "
291 "Enter the line number that you wish to go to and hit "
292 "Enter. If there are fewer lines of text than the "
293 "number you entered, you will be brought to the last line "
294 "of the file.\n\n The following function keys are "
295 "available in Go To Line mode:\n\n");
296 else if (currshortcut == insertfile_list)
297 ptr = _("Insert File Help Text\n\n "
298 "Type in the name of a file to be inserted into the current "
299 "file buffer at the current cursor location.\n\n "
300 "If you have compiled nano with multiple file buffer "
301 "support, and enable multiple buffers with the -F "
302 "or --multibuffer command line flags, the Meta-F toggle, or "
303 "a nanorc file, inserting a file will cause it to be "
304 "loaded into a separate buffer (use Meta-< and > to switch "
305 "between file buffers).\n\n If you need another blank "
306 "buffer, do not enter any filename, or type in a "
307 "nonexistent filename at the prompt and press "
308 "Enter.\n\n The following function keys are "
309 "available in Insert File mode:\n\n");
310 else if (currshortcut == writefile_list)
311 ptr = _("Write File Help Text\n\n "
312 "Type the name that you wish to save the current file "
313 "as and hit Enter to save the file.\n\n If you have "
314 "selected text with Ctrl-^, you will be prompted to "
315 "save only the selected portion to a separate file. To "
316 "reduce the chance of overwriting the current file with "
317 "just a portion of it, the current filename is not the "
318 "default in this mode.\n\n The following function keys "
319 "are available in Write File mode:\n\n");
320#ifndef DISABLE_BROWSER
321 else if (currshortcut == browser_list)
322 ptr = _("File Browser Help Text\n\n "
323 "The file browser is used to visually browse the "
324 "directory structure to select a file for reading "
325 "or writing. You may use the arrow keys or Page Up/"
326 "Down to browse through the files, and S or Enter to "
327 "choose the selected file or enter the selected "
328 "directory. To move up one level, select the directory "
329 "called \"..\" at the top of the file list.\n\n The "
330 "following function keys are available in the file "
331 "browser:\n\n");
332 else if (currshortcut == gotodir_list)
333 ptr = _("Browser Go To Directory Help Text\n\n "
334 "Enter the name of the directory you would like to "
335 "browse to.\n\n If tab completion has not been disabled, "
336 "you can use the TAB key to (attempt to) automatically "
337 "complete the directory name.\n\n The following function "
338 "keys are available in Browser Go To Directory mode:\n\n");
339#endif
340 else if (currshortcut == spell_list)
341 ptr = _("Spell Check Help Text\n\n "
342 "The spell checker checks the spelling of all text "
343 "in the current file. When an unknown word is "
344 "encountered, it is highlighted and a replacement can "
345 "be edited. It will then prompt to replace every "
346 "instance of the given misspelled word in the "
347 "current file.\n\n The following other functions are "
348 "available in Spell Check mode:\n\n");
349#ifndef NANO_SMALL
350 else if (currshortcut == extcmd_list)
351 ptr = _("External Command Help Text\n\n "
352 "This menu allows you to insert the output of a command "
353 "run by the shell into the current buffer (or a new "
354 "buffer in multibuffer mode).\n\n The following keys are "
355 "available in this mode:\n\n");
356#endif
357 else /* Default to the main help list */
358 ptr = _(" nano help text\n\n "
359 "The nano editor is designed to emulate the functionality and "
360 "ease-of-use of the UW Pico text editor. There are four main "
361 "sections of the editor: The top line shows the program "
362 "version, the current filename being edited, and whether "
363 "or not the file has been modified. Next is the main editor "
364 "window showing the file being edited. The status line is "
365 "the third line from the bottom and shows important messages. "
366 "The bottom two lines show the most commonly used shortcuts "
367 "in the editor.\n\n "
368 "The notation for shortcuts is as follows: Control-key "
369 "sequences are notated with a caret (^) symbol and are entered "
370 "with the Control (Ctrl) key. Escape-key sequences are notated "
371 "with the Meta (M) symbol and can be entered using either the "
372 "Esc, Alt or Meta key depending on your keyboard setup. The "
373 "following keystrokes are available in the main editor window. "
374 "Alternative keys are shown in parentheses:\n\n");
375
376 allocsize += strlen(ptr);
377
378 /* The space needed for the shortcut lists, at most COLS characters,
379 * plus '\n'. */
380 allocsize += (COLS + 1) * length_of_list(currshortcut);
381
382#ifndef NANO_SMALL
383 /* If we're on the main list, we also count the toggle help text.
384 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
385 * COLS - 24 characters, plus '\n'.*/
386 if (currshortcut == main_list)
387 for (t = toggles; t != NULL; t = t->next)
388 allocsize += COLS - 17;
389#endif /* !NANO_SMALL */
390
391 /* help_text has been freed and set to NULL unless the user resized
392 * while in the help screen. */
393 free(help_text);
394
395 /* Allocate space for the help text */
396 help_text = charalloc(allocsize);
397
398 /* Now add the text we want */
399 strcpy(help_text, ptr);
400 ptr = help_text + strlen(help_text);
401
402 /* Now add our shortcut info */
403 for (s = currshortcut; s != NULL; s = s->next) {
404 /* true if the character in s->altval is shown in first column */
405 int meta_shortcut = 0;
406
407 if (s->val > 0 && s->val < 32)
408 ptr += sprintf(ptr, "^%c", s->val + 64);
409#ifndef NANO_SMALL
410 else if (s->val == NANO_CONTROL_SPACE)
411 ptr += sprintf(ptr, "^%.6s", _("Space"));
412 else if (s->altval == NANO_ALT_SPACE) {
413 meta_shortcut = 1;
414 ptr += sprintf(ptr, "M-%.5s", _("Space"));
415 }
416#endif
417 else if (s->altval > 0) {
418 meta_shortcut = 1;
419 ptr += sprintf(ptr, "M-%c", s->altval -
420 (('A' <= s->altval && s->altval <= 'Z') ||
421 'a' <= s->altval ? 32 : 0));
422 }
423 /* Hack */
424 else if (s->val >= 'a') {
425 meta_shortcut = 1;
426 ptr += sprintf(ptr, "M-%c", s->val - 32);
427 }
428
429 *(ptr++) = '\t';
430
431 if (s->misc1 > KEY_F0 && s->misc1 <= KEY_F(64))
432 ptr += sprintf(ptr, "(F%d)", s->misc1 - KEY_F0);
433
434 *(ptr++) = '\t';
435
436 if (!meta_shortcut && s->altval > 0)
437 ptr += sprintf(ptr, "(M-%c)", s->altval -
438 (('A' <= s->altval && s->altval <= 'Z') || 'a' <= s->altval
439 ? 32 : 0));
440
441 *(ptr++) = '\t';
442
443 assert(s->help != NULL);
444 ptr += sprintf(ptr, "%.*s\n", COLS - 24, s->help);
445 }
446
447#ifndef NANO_SMALL
448 /* And the toggles... */
449 if (currshortcut == main_list)
450 for (t = toggles; t != NULL; t = t->next) {
451 ptr += sprintf(ptr, "M-%c\t\t\t", t->val - 32);
452 assert(t->desc != NULL);
453 ptr += sprintf(ptr, _("%.*s enable/disable\n"), COLS - 24, t->desc);
454 }
455#endif /* !NANO_SMALL */
456
457 /* If all went well, we didn't overwrite the allocated space for
458 help_text. */
459 assert(strlen(help_text) < allocsize);
460}
461#endif
462
463/* Create a new filestruct node. Note that we specifically do not set
464 * prevnode->next equal to the new line. */
465filestruct *make_new_node(filestruct *prevnode)
466{
467 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
468
469 newnode->data = NULL;
470 newnode->prev = prevnode;
471 newnode->next = NULL;
472 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
473
474 return newnode;
475}
476
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000477/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000478filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000479{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000480 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000481
Chris Allegretta6df90f52002-07-19 01:08:59 +0000482 assert(src != NULL);
483
Chris Allegretta88b09152001-05-17 11:35:43 +0000484 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000485 dst->next = src->next;
486 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000487 strcpy(dst->data, src->data);
488 dst->lineno = src->lineno;
489
490 return dst;
491}
492
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000493/* Splice a node into an existing filestruct. */
494void splice_node(filestruct *begin, filestruct *newnode, filestruct *end)
495{
496 if (newnode != NULL) {
497 newnode->next = end;
498 newnode->prev = begin;
499 }
500 if (begin != NULL)
501 begin->next = newnode;
502 if (end != NULL)
503 end->prev = newnode;
504}
505
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000506/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000507void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000508{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000509 assert(fileptr != NULL);
510
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000511 if (fileptr->prev != NULL)
512 fileptr->prev->next = fileptr->next;
513
514 if (fileptr->next != NULL)
515 fileptr->next->prev = fileptr->prev;
516}
517
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000518/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000519void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000520{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000521 if (fileptr != NULL) {
522 if (fileptr->data != NULL)
523 free(fileptr->data);
524 free(fileptr);
525 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000526}
527
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000528/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000529filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000530{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000531 filestruct *head; /* copy of src, top of the copied list */
532 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000533
Chris Allegretta6df90f52002-07-19 01:08:59 +0000534 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000535
Chris Allegretta6df90f52002-07-19 01:08:59 +0000536 prev = copy_node(src);
537 prev->prev = NULL;
538 head = prev;
539 src = src->next;
540 while (src != NULL) {
541 prev->next = copy_node(src);
542 prev->next->prev = prev;
543 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000544
Chris Allegretta6df90f52002-07-19 01:08:59 +0000545 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000546 }
547
Chris Allegretta6df90f52002-07-19 01:08:59 +0000548 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000549 return head;
550}
551
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000552/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000553void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000554{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000555 if (src != NULL) {
556 while (src->next != NULL) {
557 src = src->next;
558 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000559#ifdef DEBUG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000560 fprintf(stderr, _("delete_node(): free'd a node, YAY!\n"));
561#endif
562 }
563 delete_node(src);
564#ifdef DEBUG
565 fprintf(stderr, _("delete_node(): free'd last node.\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000566#endif
567 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000568}
569
Chris Allegretta6df90f52002-07-19 01:08:59 +0000570void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000571{
572 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000573 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000574
Chris Allegretta6df90f52002-07-19 01:08:59 +0000575 assert(fileage == NULL || fileage != fileage->next);
576 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000577 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000578}
579
Chris Allegretta6df90f52002-07-19 01:08:59 +0000580void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000581{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000582 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000583 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000584 else {
585 int lineno = fileptr->prev->lineno;
586
587 assert(fileptr != fileptr->next);
588 for (; fileptr != NULL; fileptr = fileptr->next)
589 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000590 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000591}
592
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000593/* Print one usage string to the screen, removes lots of duplicate
Chris Allegretta6df90f52002-07-19 01:08:59 +0000594 * strings to translate and takes out the parts that shouldn't be
595 * translatable (the flag names). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000596void print1opt(const char *shortflag, const char *longflag,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000597 const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000598{
599 printf(" %s\t", shortflag);
600 if (strlen(shortflag) < 8)
601 printf("\t");
602
603#ifdef HAVE_GETOPT_LONG
604 printf("%s\t", longflag);
605 if (strlen(longflag) < 8)
606 printf("\t\t");
607 else if (strlen(longflag) < 16)
608 printf("\t");
609#endif
610
611 printf("%s\n", desc);
612}
613
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000614void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000615{
616#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000617 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
618 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000619#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000620 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
621 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000622#endif /* HAVE_GETOPT_LONG */
623
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000624 print1opt("-h, -?", "--help", _("Show this message"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000625 print1opt(_("+LINE"), "", _("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000626#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000627 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000628 print1opt("-D", "--dos", _("Write file in DOS format"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000629#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000630#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000631 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000632#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000633#ifdef ENABLE_NANORC
634 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
635#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000636 print1opt("-K", "--keypad", _("Use alternate keypad routines"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000637#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000638 print1opt("-M", "--mac", _("Write file in Mac format"));
639 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000640#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000641#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000642 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000643#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000644#ifdef HAVE_REGEX_H
645 print1opt("-R", "--regexp", _("Do regular expression searches"));
646#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000647#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000648 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000649#endif
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000650 print1opt(_("-T [num]"), _("--tabsize=[num]"), _("Set width of a tab to num"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000651 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000652#ifdef ENABLE_COLOR
653 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
654#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000655 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000656#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000657 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
658 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000659#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000660 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
Chris Allegretta84de5522001-04-12 14:51:48 +0000661#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000662#ifdef NCURSES_MOUSE_VERSION
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000663 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000664#endif
665#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000666#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000667 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000668#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000669 print1opt("-p", "--pico", _("Emulate Pico as closely as possible"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000670#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000671 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000672#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000673#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000674 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000675#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000676 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
677 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000678#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000679 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000680#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000681 print1opt("-x", "--nohelp", _("Don't show help window"));
682 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000683
684 /* this is a special case */
685 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000686
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000687 exit(0);
688}
689
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000690void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000691{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000692 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000693 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000694 printf(_
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000695 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000696 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000697
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000698#ifdef DEBUG
699 printf(" --enable-debug");
700#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000701#ifdef NANO_EXTRA
702 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000703#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000704#ifdef NANO_SMALL
705 printf(" --enable-tiny");
706#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000707#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000708 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000709#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000710#ifdef DISABLE_HELP
711 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000712#endif
713#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000714 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000715#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000716#ifdef DISABLE_MOUSE
717 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000718#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000719#ifdef DISABLE_OPERATINGDIR
720 printf(" --disable-operatingdir");
721#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000722#ifdef DISABLE_SPELLER
723 printf(" --disable-speller");
724#endif
725#ifdef DISABLE_TABCOMP
726 printf(" --disable-tabcomp");
727#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000728#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000729#ifdef DISABLE_WRAPPING
730 printf(" --disable-wrapping");
731#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000732#ifdef ENABLE_COLOR
733 printf(" --enable-color");
734#endif
735#ifdef ENABLE_MULTIBUFFER
736 printf(" --enable-multibuffer");
737#endif
738#ifdef ENABLE_NANORC
739 printf(" --enable-nanorc");
740#endif
741#ifdef ENABLE_UNDO
742 printf(" --enable-undo");
743#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000744#ifdef USE_SLANG
745 printf(" --with-slang");
746#endif
747 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000748}
749
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000750/* Stuff we do when we abort from programs and want to clean up the
751 * screen. This doesn't do much right now. */
752void do_early_abort(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000753{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000754 blank_statusbar_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000755}
756
757int no_help(void)
758{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000759 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000760}
761
Chris Allegrettad865da12002-07-29 23:46:38 +0000762#if defined(DISABLE_JUSTIFY) || defined(DISABLE_SPELLER) || defined(DISABLE_HELP) || defined(NANO_SMALL)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000763void nano_disabled_msg(void)
764{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000765 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000766}
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000767#endif
Chris Allegrettaff269f82000-12-01 18:46:01 +0000768
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000769#ifndef NANO_SMALL
770static int pid; /* This is the PID of the newly forked process
771 * below. It must be global since the signal
772 * handler needs it. */
773
774RETSIGTYPE cancel_fork(int signal)
775{
776 if (kill(pid, SIGKILL)==-1) nperror("kill");
777}
778
779int open_pipe(const char *command)
780{
781 int fd[2];
782 FILE *f;
783 struct sigaction oldaction, newaction;
784 /* original and temporary handlers for SIGINT */
785#ifdef _POSIX_VDISABLE
786 struct termios term, newterm;
787#endif /* _POSIX_VDISABLE */
788 int cancel_sigs = 0;
789 /* cancel_sigs==1 means that sigaction failed without changing the
790 * signal handlers. cancel_sigs==2 means the signal handler was
791 * changed, but the tcsetattr didn't succeed.
792 * I use this variable since it is important to put things back when
793 * we finish, even if we get errors. */
794
795 /* Make our pipes. */
796
797 if (pipe(fd) == -1) {
798 statusbar(_("Could not pipe"));
799 return 1;
800 }
801
802 /* Fork a child. */
803
804 if ((pid = fork()) == 0) {
805 close(fd[0]);
806 dup2(fd[1], fileno(stdout));
807 dup2(fd[1], fileno(stderr));
808 /* If execl() returns at all, there was an error. */
809
810 execl("/bin/sh","sh","-c",command,0);
811 exit(0);
812 }
813
814 /* Else continue as parent. */
815
816 close(fd[1]);
817
818 if (pid == -1) {
819 close(fd[0]);
820 statusbar(_("Could not fork"));
821 return 1;
822 }
823
824 /* Before we start reading the forked command's output, we set
825 * things up so that ^C will cancel the new process. */
826 if (sigaction(SIGINT, NULL, &newaction)==-1) {
827 cancel_sigs = 1;
828 nperror("sigaction");
829 } else {
830 newaction.sa_handler = cancel_fork;
831 if (sigaction(SIGINT, &newaction, &oldaction)==-1) {
832 cancel_sigs = 1;
833 nperror("sigaction");
834 }
835 }
836 /* Note that now oldaction is the previous SIGINT signal handler,
837 * to be restored later. */
838
839 /* See if the platform supports disabling individual control
840 * characters. */
841#ifdef _POSIX_VDISABLE
842 if (!cancel_sigs && tcgetattr(0, &term) == -1) {
843 cancel_sigs = 2;
844 nperror("tcgetattr");
845 }
846 if (!cancel_sigs) {
847 newterm = term;
848 /* Grab oldterm's VINTR key :-) */
849 newterm.c_cc[VINTR] = oldterm.c_cc[VINTR];
850 if (tcsetattr(0, TCSANOW, &newterm) == -1) {
851 cancel_sigs = 2;
852 nperror("tcsetattr");
853 }
854 }
855#endif /* _POSIX_VDISABLE */
856
857 f = fdopen(fd[0], "rb");
858 if (!f)
859 nperror("fdopen");
860
861 read_file(f, "stdin", 0);
862 /* if multibuffer mode is on, we could be here in view mode; if so,
863 don't set the modification flag */
864 if (!ISSET(VIEW_MODE))
865 set_modified();
866
867 if (wait(NULL) == -1)
868 nperror("wait");
869
870#ifdef _POSIX_VDISABLE
871 if (!cancel_sigs && tcsetattr(0, TCSANOW, &term) == -1)
872 nperror("tcsetattr");
873#endif /* _POSIX_VDISABLE */
874
875 if (cancel_sigs!=1 && sigaction(SIGINT, &oldaction, NULL) == -1)
876 nperror("sigaction");
877
878 return 0;
879}
880#endif /* NANO_SMALL */
881
882#ifndef DISABLE_MOUSE
883#ifdef NCURSES_MOUSE_VERSION
884void do_mouse(void)
885{
886 MEVENT mevent;
887 int currslen;
888 const shortcut *s = currshortcut;
889
890 if (getmouse(&mevent) == ERR)
891 return;
892
893 /* If mouse not in edit or bottom window, return */
894 if (wenclose(edit, mevent.y, mevent.x)) {
895
896 /* Don't let people screw with the marker when they're in a
897 * subfunction. */
898 if (currshortcut != main_list)
899 return;
900
901 /* Subtract out size of topwin. Perhaps we need a constant
902 * somewhere? */
903 mevent.y -= 2;
904
905 /* Selecting where the cursor is sets the mark. Selecting
906 * beyond the line length with the cursor at the end of the line
907 * sets the mark as well. */
908 if ((mevent.y == current_y) &&
909 ((mevent.x == current_x) || (current_x == strlen(current->data)
910 && (mevent.x >
911 strlen(current->data))))) {
912 if (ISSET(VIEW_MODE)) {
913 print_view_warning();
914 return;
915 }
916 do_mark();
917 } else if (mevent.y > current_y) {
918 while (mevent.y > current_y) {
919 if (current->next != NULL)
920 current = current->next;
921 else
922 break;
923 current_y++;
924 }
925 } else if (mevent.y < current_y) {
926 while (mevent.y < current_y) {
927 if (current->prev != NULL)
928 current = current->prev;
929 else
930 break;
931 current_y--;
932 }
933 }
934 current_x = actual_x(current, mevent.x);
935 placewewant = current_x;
936 update_cursor();
937 edit_refresh();
938 } else if (wenclose(bottomwin, mevent.y, mevent.x) && !ISSET(NO_HELP)) {
939 int i, k;
940
941 if (currshortcut == main_list)
942 currslen = MAIN_VISIBLE;
943 else
944 currslen = length_of_list(currshortcut);
945
946 if (currslen < 2)
947 k = COLS / 6;
948 else
949 k = COLS / ((currslen + (currslen %2)) / 2);
950
951 /* Determine what shortcut list was clicked */
952 mevent.y -= (editwinrows + 3);
953
954 if (mevent.y < 0) /* They clicked on the statusbar */
955 return;
956
957 /* Don't select stuff beyond list length */
958 if (mevent.x / k >= currslen)
959 return;
960
961 for (i = 0; i < (mevent.x / k) * 2 + mevent.y; i++)
962 s = s->next;
963
964 /* And ungetch that value */
965 ungetch(s->val);
966
967 /* And if it's an alt-key sequence, we should probably send alt
968 too ;-) */
969 if (s->val >= 'a' && s->val <= 'z')
970 ungetch(27);
971 }
972}
973#endif
974#endif
975
Chris Allegretta6df90f52002-07-19 01:08:59 +0000976/* The user typed a printable character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000977void do_char(char ch)
978{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000979 size_t current_len = strlen(current->data);
980#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
981 int refresh = 0;
982 /* Do we have to run edit_refresh(), or can we get away with
983 * update_line()? */
984#endif
985
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000986 /* magic-line: when a character is inserted on the current magic line,
987 * it means we need a new one! */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000988 if (filebot == current && current->data[0] == '\0') {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000989 new_magicline();
Chris Allegretta28a0f892000-07-05 22:47:54 +0000990 fix_editbot();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000991 }
992
Chris Allegretta6df90f52002-07-19 01:08:59 +0000993 /* more dangerousness fun =) */
994 current->data = nrealloc(current->data, current_len + 2);
995 assert(current_x <= current_len);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000996 memmove(&current->data[current_x + 1],
997 &current->data[current_x],
Chris Allegretta6df90f52002-07-19 01:08:59 +0000998 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000999 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001000 totsize++;
1001 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001002
Chris Allegretta6df90f52002-07-19 01:08:59 +00001003#ifndef NANO_SMALL
1004 /* note that current_x has not yet been incremented */
1005 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001006 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +00001007#endif
1008
Chris Allegretta6df90f52002-07-19 01:08:59 +00001009 do_right();
1010
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001011#ifndef DISABLE_WRAPPING
Chris Allegrettadffa2072002-07-24 01:02:26 +00001012 if (!ISSET(NO_WRAP) && ch != '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001013 refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001014#endif
1015
Chris Allegretta6df90f52002-07-19 01:08:59 +00001016#ifdef ENABLE_COLOR
1017 refresh = 1;
1018#endif
1019
1020#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
1021 if (refresh)
1022 edit_refresh();
1023#endif
1024
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001025 check_statblank();
1026 UNSET(KEEP_CUTBUFFER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001027}
1028
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001029int do_backspace(void)
1030{
1031 int refresh = 0;
1032 if (current_x > 0) {
1033 assert(current_x <= strlen(current->data));
1034 /* Let's get dangerous */
1035 memmove(&current->data[current_x - 1], &current->data[current_x],
1036 strlen(current->data) - current_x + 1);
1037#ifdef DEBUG
1038 fprintf(stderr, _("current->data now = \"%s\"\n"), current->data);
1039#endif
1040 align(&current->data);
1041#ifndef NANO_SMALL
1042 if (current_x <= mark_beginx && mark_beginbuf == current)
1043 mark_beginx--;
1044#endif
1045 do_left();
1046#ifdef ENABLE_COLOR
1047 refresh = 1;
1048#endif
1049 } else {
1050 filestruct *previous;
1051 const filestruct *tmp;
1052
1053 if (current == fileage)
1054 return 0; /* Can't delete past top of file */
1055
1056 previous = current->prev;
1057 current_x = strlen(previous->data);
1058 placewewant = strlenpt(previous->data);
1059#ifndef NANO_SMALL
1060 if (current == mark_beginbuf) {
1061 mark_beginx += current_x;
1062 mark_beginbuf = previous;
1063 }
1064#endif
1065 previous->data = nrealloc(previous->data,
1066 current_x + strlen(current->data) + 1);
1067 strcpy(previous->data + current_x, current->data);
1068
1069 unlink_node(current);
1070 delete_node(current);
1071 tmp = current;
1072 current = (previous->next ? previous->next : previous);
1073 renumber(current);
1074 /* We had to renumber before doing update_line. */
1075 if (tmp == edittop)
1076 page_up();
1077
1078 /* Ooops, sanity check */
1079 if (tmp == filebot) {
1080 filebot = current;
1081 editbot = current;
1082
1083 /* Recreate the magic line if we're deleting it AND if the
1084 line we're on now is NOT blank. if it is blank we
1085 can just use IT for the magic line. This is how Pico
1086 appears to do it, in any case. */
1087 if (current->data[0] != '\0') {
1088 new_magicline();
1089 fix_editbot();
1090 }
1091 }
1092
1093 current = previous;
1094 if (current_y > 0)
1095 current_y--;
1096 totlines--;
1097#ifdef DEBUG
1098 fprintf(stderr, _("After, data = \"%s\"\n"), current->data);
1099#endif
1100 UNSET(KEEP_CUTBUFFER);
1101 refresh = 1;
1102 }
1103
1104 totsize--;
1105 set_modified();
1106 if (refresh)
1107 edit_refresh();
1108 return 1;
1109}
1110
1111int do_delete(void)
1112{
1113 int refresh = 0;
1114
1115 /* blbf -> blank line before filebot (see below) */
1116 int blbf = 0;
1117
1118 if (current->next == filebot && current->data[0] == '\0')
1119 blbf = 1;
1120
1121 placewewant = xplustabs();
1122
1123 if (current_x != strlen(current->data)) {
1124 /* Let's get dangerous */
1125 memmove(&current->data[current_x], &current->data[current_x + 1],
1126 strlen(current->data) - current_x);
1127
1128 align(&current->data);
1129#ifdef ENABLE_COLOR
1130 refresh = 1;
1131#endif
1132 } else if (current->next != NULL && (current->next != filebot || blbf)) {
1133 /* We can delete the line before filebot only if it is blank: it
1134 becomes the new magic line then. */
1135
1136 filestruct *foo;
1137
1138 current->data = nrealloc(current->data,
1139 strlen(current->data) +
1140 strlen(current->next->data) + 1);
1141 strcat(current->data, current->next->data);
1142
1143 foo = current->next;
1144 if (filebot == foo) {
1145 filebot = current;
1146 editbot = current;
1147 }
1148
1149 unlink_node(foo);
1150 delete_node(foo);
1151 renumber(current);
1152 totlines--;
1153 refresh = 1;
1154 } else
1155 return 0;
1156
1157 totsize--;
1158 set_modified();
1159 UNSET(KEEP_CUTBUFFER);
1160 update_line(current, current_x);
1161 if (refresh)
1162 edit_refresh();
1163 return 1;
1164}
1165
1166int do_tab(void)
1167{
1168 do_char('\t');
1169 return 1;
1170}
1171
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001172/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001173int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001174{
Chris Allegrettae3167732001-03-18 16:59:34 +00001175 filestruct *newnode;
Chris Allegretta68532c32001-09-17 13:49:33 +00001176 char *tmp;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001177
Chris Allegretta6df90f52002-07-19 01:08:59 +00001178 newnode = make_new_node(current);
1179 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001180 tmp = &current->data[current_x];
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001181
Chris Allegrettaff989832001-09-17 13:48:00 +00001182#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001183 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001184 if (ISSET(AUTOINDENT)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001185 int extra = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001186 const char *spc = current->data;
1187
1188 while (*spc == ' ' || *spc == '\t') {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001189 extra++;
1190 spc++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001191 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001192 /* If current_x < extra, then we are breaking the line in the
1193 * indentation. Autoindenting should add only current_x
1194 * characters of indentation. */
Chris Allegrettadab017e2002-04-23 10:56:06 +00001195 if (current_x < extra)
1196 extra = current_x;
1197 else
1198 current_x = extra;
1199 totsize += extra;
1200
1201 newnode->data = charalloc(strlen(tmp) + extra + 1);
1202 strncpy(newnode->data, current->data, extra);
1203 strcpy(&newnode->data[extra], tmp);
Chris Allegrettaff989832001-09-17 13:48:00 +00001204 } else
1205#endif
1206 {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001207 current_x = 0;
Chris Allegretta88b09152001-05-17 11:35:43 +00001208 newnode->data = charalloc(strlen(tmp) + 1);
Chris Allegrettae3167732001-03-18 16:59:34 +00001209 strcpy(newnode->data, tmp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001210 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001211 *tmp = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001212
Chris Allegretta6df90f52002-07-19 01:08:59 +00001213 if (current->next == NULL) {
Chris Allegrettae3167732001-03-18 16:59:34 +00001214 filebot = newnode;
1215 editbot = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001216 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001217 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001218
1219 totsize++;
1220 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001221 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001222 align(&current->data);
1223
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001224 /* The logic here is as follows:
1225 * -> If we are at the bottom of the buffer, we want to recenter
Chris Allegretta88520c92001-05-05 17:45:54 +00001226 * (read: rebuild) the screen and forcibly move the cursor.
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001227 * -> otherwise, we want simply to redraw the screen and update
1228 * where we think the cursor is.
1229 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001230 if (current_y == editwinrows - 1) {
Chris Allegretta234a34d2000-07-29 04:33:38 +00001231 edit_update(current, CENTER);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001232 reset_cursor();
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001233 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001234 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001235 edit_refresh();
1236 update_cursor();
1237 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001238
1239 totlines++;
1240 set_modified();
1241
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001242 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001243 return 1;
1244}
1245
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001246#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001247int do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001248{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001249 filestruct *old = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001250
Chris Allegretta6df90f52002-07-19 01:08:59 +00001251 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001252
Chris Allegretta6df90f52002-07-19 01:08:59 +00001253 /* Skip letters in this word first. */
1254 while (current->data[current_x] != '\0' &&
1255 isalnum((int)current->data[current_x]))
1256 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001257
Chris Allegretta6df90f52002-07-19 01:08:59 +00001258 for (; current != NULL; current = current->next) {
1259 while (current->data[current_x] != '\0' &&
1260 !isalnum((int)current->data[current_x]))
1261 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001262
Chris Allegretta6df90f52002-07-19 01:08:59 +00001263 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001264 break;
1265
Chris Allegretta6df90f52002-07-19 01:08:59 +00001266 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001267 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001268 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001269 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001270
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001271 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001272
Chris Allegrettad865da12002-07-29 23:46:38 +00001273 if (current->lineno >= editbot->lineno) {
1274 /* If we're on the last line, don't center the screen. */
1275 if (current->lineno == filebot->lineno)
1276 edit_refresh();
1277 else
1278 edit_update(current, CENTER);
1279 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001280 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001281 /* If we've jumped lines, refresh the old line. We can't just
1282 use current->prev here, because we may have skipped over some
1283 blank lines, in which case the previous line is the wrong
1284 one. */
1285 if (current != old) {
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001286 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001287 /* If the mark was set, then the lines between old and
1288 current have to be updated too. */
1289 if (ISSET(MARK_ISSET)) {
1290 while (old->next != current) {
1291 old = old->next;
1292 update_line(old, 0);
1293 }
1294 }
1295 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001296 update_line(current, current_x);
1297 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001298 return 0;
1299}
1300
Chris Allegretta6df90f52002-07-19 01:08:59 +00001301/* The same thing for backwards. */
1302int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001303{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001304 filestruct *old = current;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001305
Chris Allegretta6df90f52002-07-19 01:08:59 +00001306 assert(current != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001307
Chris Allegretta6df90f52002-07-19 01:08:59 +00001308 /* Skip letters in this word first. */
1309 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1310 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001311
Chris Allegretta6df90f52002-07-19 01:08:59 +00001312 for (; current != NULL; current = current->prev) {
1313 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1314 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001315
Chris Allegretta6df90f52002-07-19 01:08:59 +00001316 if (current_x >= 0)
1317 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001318
Chris Allegretta6df90f52002-07-19 01:08:59 +00001319 if (current->prev != NULL)
1320 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001321 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001322
Chris Allegretta6df90f52002-07-19 01:08:59 +00001323 if (current != NULL) {
1324 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1325 current_x--;
1326 } else {
1327 current = fileage;
1328 current_x = 0;
1329 }
1330
Chris Allegretta76e291b2001-10-14 19:05:10 +00001331 placewewant = xplustabs();
1332
Chris Allegrettad865da12002-07-29 23:46:38 +00001333 if (current->lineno <= edittop->lineno) {
1334 /* If we're on the first line, don't center the screen. */
1335 if (current->lineno == fileage->lineno)
1336 edit_refresh();
1337 else
1338 edit_update(current, CENTER);
1339 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001340 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001341 /* If we've jumped lines, refresh the old line. We can't just
1342 use current->prev here, because we may have skipped over some
1343 blank lines, in which case the previous line is the wrong
1344 one. */
1345 if (current != old) {
Chris Allegretta76e291b2001-10-14 19:05:10 +00001346 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001347 /* If the mark was set, then the lines between old and
1348 current have to be updated too. */
1349 if (ISSET(MARK_ISSET)) {
1350 while (old->prev != current) {
1351 old = old->prev;
1352 update_line(old, 0);
1353 }
1354 }
1355 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001356 update_line(current, current_x);
1357 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001358 return 0;
1359}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001360#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001361
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001362int do_mark(void)
1363{
1364#ifdef NANO_SMALL
1365 nano_disabled_msg();
1366#else
1367 if (!ISSET(MARK_ISSET)) {
1368 statusbar(_("Mark Set"));
1369 SET(MARK_ISSET);
1370 mark_beginbuf = current;
1371 mark_beginx = current_x;
1372 } else {
1373 statusbar(_("Mark UNset"));
1374 UNSET(MARK_ISSET);
1375 edit_refresh();
1376 }
1377#endif
1378 return 1;
1379}
1380
1381void wrap_reset(void)
1382{
1383 UNSET(SAMELINEWRAP);
1384}
1385
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001386#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001387/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001388 * moved forward since the last typed character. Return value:
1389 * whether we wrapped. */
1390int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001391{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001392 size_t len = strlen(inptr->data); /* length of the line we wrap */
1393 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001394 int wrap_loc = -1; /* index of inptr->data where we wrap */
1395 int word_back = -1;
1396#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001397 const char *indentation = NULL;
1398 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001399 int indent_len = 0; /* strlen(indentation) */
1400#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001401 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001402 int after_break_len; /* strlen(after_break) */
1403 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001404 const char *wrap_line = NULL;
1405 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001406 int wrap_line_len = 0; /* strlen(wrap_line) */
1407 char *newline = NULL; /* the line we create */
1408 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001409
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001410/* There are three steps. First, we decide where to wrap. Then, we
1411 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001412
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001413/* Step 1, finding where to wrap. We are going to add a new-line
1414 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001415 * location of this replacement.
1416 *
1417 * Where should we break the line? We need the last "legal wrap point"
1418 * such that the last word before it ended at or before fill. If there
1419 * is no such point, we settle for the first legal wrap point.
1420 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001421 * A "legal wrap point" is a white-space character that is not followed by
1422 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001423 *
1424 * If there is no legal wrap point or we found the last character of the
1425 * line, we should return without wrapping.
1426 *
1427 * Note that the initial indentation does not count as a legal wrap
1428 * point if we are going to auto-indent!
1429 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001430 * Note that the code below could be optimised, by not calling strnlenpt()
1431 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001432
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001433#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001434 if (ISSET(AUTOINDENT))
1435 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001436#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001437 wrap_line = inptr->data + i;
1438 for(; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001439 /* record where the last word ended */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001440 if (*wrap_line != ' ' && *wrap_line != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001441 word_back = i;
1442 /* if we have found a "legal wrap point" and the current word
1443 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001444 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001445 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001446 /* we record the latest "legal wrap point" */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001447 if (word_back != i && wrap_line[1] != ' ' && wrap_line[1] != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001448 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001449 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001450 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001451 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001452
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001453/* Step 2, making the new wrap line. It will consist of indentation +
1454 * after_break + " " + wrap_line (although indentation and wrap_line are
1455 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001456
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001457 /* after_break is the text that will be moved to the next line. */
1458 after_break = inptr->data + wrap_loc + 1;
1459 after_break_len = len - wrap_loc - 1;
1460 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001461
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001462 /* new_line_len will later be increased by the lengths of indentation
1463 * and wrap_line. */
1464 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001465
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001466 /* We prepend the wrapped text to the next line, if the flag is set,
1467 * and there is a next line, and prepending would not make the line
1468 * too long. */
Adam Rogoyski0223d6f2000-06-17 20:36:35 +00001469 if (ISSET(SAMELINEWRAP) && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001470 wrap_line = inptr->next->data;
1471 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001472
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001473 /* +1 for the space between after_break and wrap_line */
1474 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1475 wrapping = 1;
1476 new_line_len += (1 + wrap_line_len);
1477 }
1478 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001479
Chris Allegrettaff989832001-09-17 13:48:00 +00001480#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001481 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001482 /* Indentation comes from the next line if wrapping, else from
1483 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001484 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001485 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001486 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001487 /* The wrap_line text should not duplicate indentation.
1488 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001489 wrap_line += indent_len;
1490 else
1491 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001492 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001493#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001494
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001495 /* Now we allocate the new line and copy into it. */
1496 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1497 *newline = '\0';
1498
1499#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001500 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001501 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001502 newline[indent_len] = '\0';
1503 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001504#endif
1505 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001506 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001507 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001508 null_at(&inptr->data, wrap_loc + 1);
1509 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001510 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001511 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001512 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001513 * in a tab or a space, we don't add a space and decrement
1514 * totsize to account for that. */
David Lawrence Ramsey7c4222c2002-09-26 22:49:56 +00001515 if (!isspace(newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001516 strcat(newline, " ");
1517 else
1518 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001519 strcat(newline, wrap_line);
1520 free(inptr->next->data);
1521 inptr->next->data = newline;
1522 } else {
1523 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001524
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001525 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001526 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001527#ifndef NANO_SMALL
1528 totsize += indent_len;
1529#endif
1530 totlines++;
1531 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001532 temp->prev = inptr;
1533 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001534 temp->prev->next = temp;
1535 /* If !temp->next, then temp is the last line of the file, so we
Chris Allegretta81dea022002-09-21 02:19:45 +00001536 * must set filebot. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001537 if (temp->next)
1538 temp->next->prev = temp;
1539 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001540 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001541 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001542
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001543/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1544 * other sundry things. */
1545
1546 /* later wraps of this line will be prepended to the next line. */
1547 SET(SAMELINEWRAP);
1548
1549 /* Each line knows its line number. We recalculate these if we
1550 * inserted a new line. */
1551 if (!wrapping)
1552 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001553
Chris Allegretta6df90f52002-07-19 01:08:59 +00001554 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001555 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001556 current = current->next;
1557 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001558#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001559 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001560#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001561 wrap_loc + 1;
1562 wrap_reset();
1563 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001564 }
1565
Chris Allegretta6df90f52002-07-19 01:08:59 +00001566#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001567 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001568 * If it was on the next line and we wrapped, we must move it
1569 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001570 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1571 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001572 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001573 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001574 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001575#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001576
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001577 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001578 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001579
1580 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001581}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001582#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001583
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001584#ifndef DISABLE_SPELLER
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001585int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001586{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001587 char *save_search;
1588 char *save_replace;
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001589 filestruct *begin;
Chris Allegretta23b74b22002-01-21 20:32:22 +00001590 int i = 0, j = 0, beginx, beginx_top, reverse_search_set;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001591#ifndef NANO_SMALL
1592 int mark_set;
1593#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001594
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001595 /* save where we are */
1596 begin = current;
1597 beginx = current_x + 1;
1598
Chris Allegretta23b74b22002-01-21 20:32:22 +00001599 /* Make sure Spell Check goes forward only */
1600 reverse_search_set = ISSET(REVERSE_SEARCH);
1601 UNSET(REVERSE_SEARCH);
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 Allegrettad00e6df2000-11-29 04:33:26 +00001624 edit_update(fileage, TOP);
1625
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001626 while (1) {
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001627 /* make sure word is still mis-spelt (i.e. when multi-errors) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001628 if (findnextstr(TRUE, FALSE, fileage, beginx_top, word) != NULL) {
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001629
Chris Allegretta6df90f52002-07-19 01:08:59 +00001630 /* find whole words only */
1631 if (!is_whole_word(current_x, current->data, word))
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001632 continue;
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001633
Chris Allegretta6df90f52002-07-19 01:08:59 +00001634 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001635
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001636 /* allow replace word to be corrected */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001637 i = statusq(0, spell_list, last_replace, _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001638
Chris Allegretta6df90f52002-07-19 01:08:59 +00001639 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001640
1641 /* start from the start of this line again */
1642 current = fileage;
1643 current_x = beginx_top;
1644
1645 search_last_line = FALSE;
1646
Chris Allegretta6df90f52002-07-19 01:08:59 +00001647 if (strcmp(word, answer)) {
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001648 j = i;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001649 do_replace_loop(word, fileage, &beginx_top, TRUE, &j);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001650 }
Chris Allegretta80838272001-12-02 06:03:22 +00001651 }
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001652 break;
Rocco Corsi562964d2002-01-13 03:18:03 +00001653 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001654
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001655 /* restore the search/replace strings */
Chris Allegrettabef12972002-03-06 03:30:40 +00001656 free(last_search); last_search=save_search;
1657 free(last_replace); last_replace=save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001658
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001659 /* restore where we were */
1660 current = begin;
1661 current_x = beginx - 1;
1662
Chris Allegretta23b74b22002-01-21 20:32:22 +00001663 /* restore Search/Replace direction */
1664 if (reverse_search_set)
1665 SET(REVERSE_SEARCH);
1666
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001667#ifndef NANO_SMALL
1668 /* restore marking highlight */
1669 if (mark_set)
1670 SET(MARK_ISSET);
1671#endif
1672
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001673 edit_update(current, CENTER);
1674
1675 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;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001686 int in_fd[2], tempfile_fd, spell_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001687 pid_t pid_spell;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001688
Chris Allegretta271e9722000-11-10 18:15:43 +00001689 /* Create a pipe to spell program */
1690
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001691 if (pipe(in_fd) == -1)
1692 return FALSE;
1693
Chris Allegretta271e9722000-11-10 18:15:43 +00001694 /* A new process to run spell in */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001695
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001696 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001697
1698 /* Child continues, (i.e. future spell process) */
1699
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001700 close(in_fd[0]);
1701
Chris Allegretta271e9722000-11-10 18:15:43 +00001702 /* replace the standard in with the tempfile */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001703
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001704 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001705 close(in_fd[1]);
1706 exit(1);
1707 }
1708
1709 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001710 close(tempfile_fd);
1711 close(in_fd[1]);
1712 exit(1);
1713 }
1714 close(tempfile_fd);
1715
1716 /* send spell's standard out to the pipe */
1717
1718 if (dup2(in_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001719 close(in_fd[1]);
1720 exit(1);
1721 }
1722 close(in_fd[1]);
1723
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 Allegretta271e9722000-11-10 18:15:43 +00001734 close(in_fd[1]);
1735
1736 /* Child process was not forked successfully */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001737
1738 if (pid_spell < 0) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001739 close(in_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001740 return FALSE;
1741 }
1742
Chris Allegretta271e9722000-11-10 18:15:43 +00001743 /* Get system pipe buffer size */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001744
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001745 if ((pipe_buff_size = fpathconf(in_fd[0], _PC_PIPE_BUF)) < 1) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001746 close(in_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001747 return FALSE;
Chris Allegretta271e9722000-11-10 18:15:43 +00001748 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001749
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001750 /* Read-in the returned spelling errors */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001751
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001752 read_buff_read = 0;
1753 read_buff_size = pipe_buff_size + 1;
1754 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001755
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001756 while ((bytesread = read(in_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001757 read_buff_read += bytesread;
1758 read_buff_size += pipe_buff_size;
1759 read_buff = read_buff_ptr = nrealloc(read_buff, read_buff_size);
1760 read_buff_ptr += read_buff_read;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001761 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001762
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001763 *read_buff_ptr = (char) NULL;
Chris Allegretta271e9722000-11-10 18:15:43 +00001764 close(in_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001765
1766 /* Process the spelling errors */
1767
1768 read_buff_word = read_buff_ptr = read_buff;
1769
1770 while (*read_buff_ptr) {
1771
1772 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
1773 *read_buff_ptr = (char) NULL;
1774 if (read_buff_word != read_buff_ptr) {
1775 if (!do_int_spell_fix(read_buff_word)) {
1776 read_buff_word = read_buff_ptr;
1777 break;
1778 }
1779 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001780 read_buff_word = read_buff_ptr + 1;
1781 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001782 read_buff_ptr++;
1783 }
1784
1785 /* special case where last word doesn't end with \n or \r */
1786 if (read_buff_word != read_buff_ptr)
1787 do_int_spell_fix(read_buff_word);
1788
Chris Allegretta271e9722000-11-10 18:15:43 +00001789 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001790 replace_abort();
1791
Chris Allegretta271e9722000-11-10 18:15:43 +00001792 /* Process end of spell process */
1793
1794 wait(&spell_status);
1795 if (WIFEXITED(spell_status)) {
1796 if (WEXITSTATUS(spell_status) != 0)
1797 return FALSE;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001798 } else
Chris Allegretta271e9722000-11-10 18:15:43 +00001799 return FALSE;
1800
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001801 return TRUE;
1802}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001803
Chris Allegretta6df90f52002-07-19 01:08:59 +00001804/* External spell checking. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001805int do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001806{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001807 int alt_spell_status, lineno_cur = current->lineno;
1808 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001809 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001810 char *ptr;
1811 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001812 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001813#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001814 int mark_set = ISSET(MARK_ISSET);
1815 int mbb_lineno_cur = 0;
1816 /* We're going to close the current file, and open the output of
1817 the alternate spell command. The line that mark_beginbuf
1818 points to will be freed, so we save the line number and restore
1819 afterwards. */
1820
1821 if (mark_set) {
1822 mbb_lineno_cur = mark_beginbuf->lineno;
1823 UNSET(MARK_ISSET);
1824 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001825#endif
1826
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001827 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001828
Chris Allegrettae434b452001-01-27 19:25:00 +00001829 /* Set up an argument list to pass the execvp function */
1830 if (spellargs == NULL) {
1831 spellargs = nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001832
Chris Allegrettae434b452001-01-27 19:25:00 +00001833 spellargs[0] = strtok(alt_speller, " ");
1834 while ((ptr = strtok(NULL, " ")) != NULL) {
1835 arglen++;
1836 spellargs = nrealloc(spellargs, arglen * sizeof(char *));
1837 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001838 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001839 spellargs[arglen - 1] = NULL;
1840 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001841 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001842
1843 /* Start a new process for the alternate speller */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001844 if ((pid_spell = fork()) == 0) {
Chris Allegretta88520c92001-05-05 17:45:54 +00001845 /* Start alternate spell program; we are using the PATH here!?!? */
Chris Allegretta169ee842001-01-26 01:57:32 +00001846 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001847
1848 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001849 exit(1);
1850 }
1851
1852 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001853 if (pid_spell < 0)
1854 return FALSE;
1855
1856 /* Wait for alternate speller to complete */
1857
1858 wait(&alt_spell_status);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001859 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001860 return FALSE;
1861
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001862 refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001863 free_filestruct(fileage);
Chris Allegretta56214c62001-09-27 02:46:53 +00001864 global_init(1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001865 open_file(tempfile_name, 0, 1);
Rocco Corsi4dfaf932001-04-20 01:59:55 +00001866
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001867#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001868 if (mark_set) {
1869 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1870 mark_beginbuf = current;
1871 mark_beginx = current_x;
1872 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001873 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001874 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001875#endif
1876
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001877 /* go back to the old position, mark the file as modified, and make
1878 sure that the titlebar is refreshed */
1879 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001880 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001881 clearok(topwin, FALSE);
1882 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001883
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001884 return TRUE;
1885}
1886#endif
1887
1888int do_spell(void)
1889{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001890#ifdef DISABLE_SPELLER
Chris Allegrettaff269f82000-12-01 18:46:01 +00001891 nano_disabled_msg();
1892 return (TRUE);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001893#else
Chris Allegretta271e9722000-11-10 18:15:43 +00001894 char *temp;
1895 int spell_res;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001896
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001897 if ((temp = safe_tempnam(0, "nano.")) == NULL) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001898 statusbar(_("Could not create a temporary filename: %s"),
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001899 strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001900 return 0;
1901 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001902
Chris Allegrettaecc3d7f2001-06-05 23:24:55 +00001903 if (write_file(temp, 1, 0, 0) == -1) {
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001904 statusbar(_("Spell checking failed: unable to write temp file!"));
Chris Allegrettabef12972002-03-06 03:30:40 +00001905 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001906 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001907 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001908
Chris Allegrettae1f14522001-09-19 03:19:43 +00001909#ifdef ENABLE_MULTIBUFFER
1910 /* update the current open_files entry before spell-checking, in case
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001911 any problems occur */
Chris Allegretta48b06702002-02-22 04:30:50 +00001912 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001913#endif
1914
Chris Allegretta271e9722000-11-10 18:15:43 +00001915 if (alt_speller)
1916 spell_res = do_alt_speller(temp);
1917 else
1918 spell_res = do_int_speller(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001919
Chris Allegretta271e9722000-11-10 18:15:43 +00001920 remove(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001921
1922 if (spell_res)
1923 statusbar(_("Finished checking spelling"));
1924 else
1925 statusbar(_("Spell checking failed"));
1926
Chris Allegrettabef12972002-03-06 03:30:40 +00001927 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001928 return spell_res;
1929
Chris Allegrettadbc12b22000-07-03 03:10:14 +00001930#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00001931}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001932
Chris Allegrettad865da12002-07-29 23:46:38 +00001933#if !defined(DISABLE_WRAPPING) && !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001934/* The "indentation" of a line is the white-space between the quote part
1935 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001936size_t indent_length(const char *line)
1937{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001938 size_t len = 0;
1939
1940 assert(line != NULL);
1941 while (*line == ' ' || *line == '\t') {
1942 line++;
1943 len++;
1944 }
1945 return len;
1946}
Chris Allegrettadffa2072002-07-24 01:02:26 +00001947#endif /* !DISABLE_WRAPPING && !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001948
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001949#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00001950/* justify_format() replaces Tab by Space and multiple spaces by 1 (except
1951 * it maintains 2 after a . ! or ?). Note the terminating \0
1952 * counts as a space.
1953 *
1954 * If !changes_allowed and justify_format needs to make a change, it
1955 * returns 1, otherwise returns 0.
1956 *
1957 * If changes_allowed, justify_format() might make line->data
1958 * shorter, and change the actual pointer with null_at().
1959 *
1960 * justify_format will not look at the first skip characters of line.
1961 * skip should be at most strlen(line->data). The skip+1st character must
1962 * not be whitespace. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001963int justify_format(int changes_allowed, filestruct *line, size_t skip)
1964{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001965 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001966
Chris Allegretta6df90f52002-07-19 01:08:59 +00001967 /* These four asserts are assumptions about the input data. */
1968 assert(line != NULL);
1969 assert(line->data != NULL);
1970 assert(skip <= strlen(line->data));
1971 assert(line->data[skip] != ' ' && line->data[skip] != '\t');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001972
Chris Allegretta6df90f52002-07-19 01:08:59 +00001973 back = line->data + skip;
1974 front = back;
1975 for (; *front; front++) {
1976 if (*front == '\t') {
1977 if (!changes_allowed)
1978 return 1;
1979 *front = ' ';
1980 }
1981 /* these tests are safe since line->data + skip is not a space */
Chris Allegrettad865da12002-07-29 23:46:38 +00001982 if (*front == ' ' && *(front - 1) == ' ' && *(front - 2) != '.' &&
1983 *(front - 2) != '!' && *(front - 2) != '?') {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001984 /* Now *front is a space we want to remove. We do that by
1985 * simply failing to assign it to *back */
1986 if (!changes_allowed)
1987 return 1;
1988#ifndef NANO_SMALL
1989 if (mark_beginbuf == line && back - line->data < mark_beginx)
1990 mark_beginx--;
1991#endif
1992 } else {
1993 *back = *front;
1994 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001995 }
1996 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001997
1998 /* Remove spaces from the end of the line, except maintain 1 after a
1999 * sentence punctuation. */
2000 while (line->data < back && *(back-1) == ' ')
2001 back--;
2002 if (line->data < back && *back == ' ' &&
2003 (*(back-1) == '.' || *(back-1) == '!' || *(back-1) == '?'))
2004 back++;
2005 if (!changes_allowed && back != front)
2006 return 1;
2007
2008 /* This assert merely documents a fact about the loop above. */
Chris Allegrettad865da12002-07-29 23:46:38 +00002009 assert(changes_allowed || back == front);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002010
2011 /* Now back is the new end of line->data. */
2012 if (back != front) {
2013 totsize += back - line->data - strlen(line->data);
2014 null_at(&line->data, back - line->data);
2015#ifndef NANO_SMALL
2016 if (mark_beginbuf == line && back - line->data < mark_beginx)
2017 mark_beginx = back - line->data;
2018#endif
2019 }
2020 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002021}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002022
2023/* The "quote part" of a line is the largest initial substring matching
2024 * the quote string. This function returns the length of the quote part
2025 * of the given line.
2026 *
2027 * Note that if !HAVE_REGEX_H then we match concatenated copies of
2028 * quotestr. */
2029#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002030size_t quote_length(const char *line, const regex_t *qreg)
2031{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002032 regmatch_t matches;
2033 int rc = regexec(qreg, line, 1, &matches, 0);
2034
2035 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
2036 return 0;
2037 /* matches.rm_so should be 0, since the quote string should start with
2038 * the caret ^. */
2039 return matches.rm_eo;
2040}
2041#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002042size_t quote_length(const char *line)
2043{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002044 size_t qdepth = 0;
2045 size_t qlen = strlen(quotestr);
2046
2047 /* Compute quote depth level */
2048 while (!strcmp(line + qdepth, quotestr))
2049 qdepth += qlen;
2050 return qdepth;
2051}
2052#endif /* !HAVE_REGEX_H */
2053
Chris Allegretta6df90f52002-07-19 01:08:59 +00002054/* a_line and b_line are lines of text. The quotation part of a_line is
2055 * the first a_quote characters. Check that the quotation part of
2056 * b_line is the same. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002057int quotes_match(const char *a_line, size_t a_quote,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002058 IFREG(const char *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002059{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002060 /* Here is the assumption about a_quote: */
2061 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00002062 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00002063 !strncmp(a_line, b_line, a_quote);
2064}
2065
2066/* We assume a_line and b_line have no quote part. Then, we return whether
2067 * b_line could follow a_line in a paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002068size_t indents_match(const char *a_line, size_t a_indent,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002069 const char *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002070{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002071 assert(a_indent == indent_length(a_line));
2072 assert(b_indent == indent_length(b_line));
2073
2074 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2075}
2076
2077/* Put the next par_len lines, starting with first_line, in the cut
2078 * buffer. We assume there are enough lines after first_line. We leave
2079 * copies of the lines in place, too. We return the new copy of
2080 * first_line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002081filestruct *backup_lines(filestruct *first_line, size_t par_len,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002082 size_t quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002083{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002084 /* We put the original lines, not copies, into the cut buffer, just
2085 * out of a misguided sense of consistency, so if you un-cut, you
2086 * get the actual same paragraph back, not a copy. */
2087 filestruct *alice = first_line;
2088
2089 set_modified();
2090 cutbuffer = NULL;
2091 for(; par_len > 0; par_len--) {
2092 filestruct *bob = copy_node(alice);
2093
2094 if (alice == first_line)
2095 first_line = bob;
2096 if (alice == current)
2097 current = bob;
2098 if (alice == edittop)
2099 edittop = bob;
2100#ifndef NANO_SMALL
2101 if (alice == mark_beginbuf)
2102 mark_beginbuf = bob;
2103#endif
2104 justify_format(1, bob,
2105 quote_len + indent_length(bob->data + quote_len));
2106
2107 assert(alice != NULL && bob != NULL);
2108 add_to_cutbuffer(alice);
2109 splice_node(bob->prev, bob, bob->next);
2110 alice = bob->next;
2111 }
2112 return first_line;
2113}
2114
2115/* We are trying to break a chunk off line. We find the last space such
2116 * that the display length to there is at most goal + 1. If there is
2117 * no such space, and force is not 0, then we find the first space.
2118 * Anyway, we then take the last space in that group of spaces. The
2119 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002120int break_line(const char *line, int goal, int force)
2121{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002122 /* Note that we use int instead of size_t, since goal is at most COLS,
2123 * the screen width, which will always be reasonably small. */
2124 int space_loc = -1;
2125 /* Current tentative return value. Index of the last space we
2126 * found with short enough display width. */
2127 int cur_loc = 0;
2128 /* Current index in line */
2129
2130 assert(line != NULL);
2131 for(; *line != '\0' && goal >= 0; line++, cur_loc++) {
2132 if (*line == ' ')
2133 space_loc = cur_loc;
2134 assert(*line != '\t');
2135
Chris Allegrettacf287c82002-07-20 13:57:41 +00002136 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002137 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002138 else
2139 goal--;
2140 }
2141 if (goal >= 0)
2142 /* In fact, the whole line displays shorter than goal. */
2143 return cur_loc;
2144 if (space_loc == -1) {
2145 /* No space found short enough. */
2146 if (force)
2147 for(; *line != '\0'; line++, cur_loc++)
2148 if (*line == ' ' && *(line + 1) != ' ')
2149 return cur_loc;
2150 return -1;
2151 }
2152 /* Perhaps the character after space_loc is a space. But because
2153 * of justify_format, there can be only two adjacent. */
2154 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2155 *(line - cur_loc + space_loc + 1) == '\0')
2156 space_loc++;
2157 return space_loc;
2158}
2159#endif /* !DISABLE_JUSTIFY */
2160
2161/* This function justifies the current paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002162int do_justify(void)
2163{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002164#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +00002165 nano_disabled_msg();
2166 return 1;
2167#else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002168
Chris Allegretta6df90f52002-07-19 01:08:59 +00002169/* To explain the justifying algorithm, I first need to define some
2170 * phrases about paragraphs and quotation:
2171 * A line of text consists of a "quote part", followed by an
2172 * "indentation part", followed by text. The functions quote_length()
2173 * and indent_length() calculate these parts.
2174 *
2175 * A line is "part of a paragraph" if it has a part not in the quote
2176 * part or the indentation.
2177 *
2178 * A line is "the beginning of a paragraph" if it is part of a paragraph
2179 * and
2180 * 1) it is the top line of the file, or
2181 * 2) the line above it is not part of a paragraph, or
2182 * 3) the line above it does not have precisely the same quote
2183 * part, or
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002184 * 4) the indentation of this line is not an initial substring of the
Chris Allegretta6df90f52002-07-19 01:08:59 +00002185 * indentation of the previous line, or
2186 * 5) this line has no quote part and some indentation, and
2187 * AUTOINDENT is not set.
2188 * The reason for number 5) is that if AUTOINDENT is not set, then an
2189 * indented line is expected to start a paragraph, like in books. Thus,
2190 * nano can justify an indented paragraph only if AUTOINDENT is turned
2191 * on.
2192 *
2193 * A contiguous set of lines is a "paragraph" if each line is part of
2194 * a paragraph and only the first line is the beginning of a paragraph.
Chris Allegrettad4fa0d32002-03-05 19:55:55 +00002195 */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002196
Chris Allegretta6df90f52002-07-19 01:08:59 +00002197 size_t quote_len;
2198 /* Length of the initial quotation of the paragraph we justify. */
2199 size_t par_len;
2200 /* Number of lines in that paragraph. */
2201 filestruct *first_mod_line = NULL;
2202 /* Will be the first line of the resulting justified paragraph
2203 * that differs from the original. For restoring after uncut. */
2204 filestruct *last_par_line = current;
2205 /* Will be the last line of the result, also for uncut. */
2206 filestruct *cutbuffer_save = cutbuffer;
2207 /* When the paragraph gets modified, all lines from the changed
2208 * one down are stored in the cut buffer. We back up the original
2209 * to restore it later. */
2210
2211 /* We save these global variables to be restored if the user
2212 * unjustifies. Note we don't need to save totlines. */
2213 int current_x_save = current_x;
2214 int current_y_save = current_y;
2215 filestruct *current_save = current;
2216 int flags_save = flags;
2217 long totsize_save = totsize;
2218 filestruct *edittop_save = edittop;
2219 filestruct *editbot_save = editbot;
2220#ifndef NANO_SMALL
2221 filestruct *mark_beginbuf_save = mark_beginbuf;
2222 int mark_beginx_save = mark_beginx;
2223#endif
2224
2225 size_t indent_len; /* generic indentation length */
2226 filestruct *line; /* generic line of text */
2227 size_t i; /* generic loop variable */
2228
2229#ifdef HAVE_REGEX_H
2230 regex_t qreg; /* qreg is the compiled quotation regexp.
Chris Allegrettad865da12002-07-29 23:46:38 +00002231 * We no longer care about quotestr. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002232 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2233
2234 if (rc) {
2235 size_t size = regerror(rc, &qreg, NULL, 0);
2236 char *strerror = charalloc(size);
2237
2238 regerror(rc, &qreg, strerror, size);
2239 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2240 free(strerror);
2241 return -1;
2242 }
2243#endif
2244
2245 /* Here is an assumption that is always true anyway. */
2246 assert(current != NULL);
2247
2248/* Here we find the first line of the paragraph to justify. If the
2249 * current line is in a paragraph, then we move back to the first line.
2250 * Otherwise we move down to the first line that is in a paragraph. */
2251 quote_len = quote_length(IFREG(current->data, &qreg));
2252 indent_len = indent_length(current->data + quote_len);
2253
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002254 current_x = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002255 if (current->data[quote_len + indent_len] != '\0') {
2256 /* This line is part of a paragraph. So we must search back to
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002257 * the first line of this paragraph. First we check items 1) and
2258 * 3) above. */
2259 while (current->prev && quotes_match(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002260 quote_len, IFREG(current->prev->data, &qreg))) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002261 size_t temp_id_len =
Chris Allegretta6df90f52002-07-19 01:08:59 +00002262 indent_length(current->prev->data + quote_len);
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002263 /* The indentation length of the previous line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002264
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002265 /* Is this line the beginning of a paragraph, according to
2266 items 2), 5), or 4) above? If so, stop. */
2267 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
2268 (quote_len == 0 && indent_len > 0
2269#ifndef NANO_SMALL
2270 && !ISSET(AUTOINDENT)
2271#endif
2272 ) ||
2273 !indents_match(current->prev->data + quote_len,
2274 temp_id_len, current->data + quote_len, indent_len))
2275 break;
2276 indent_len = temp_id_len;
2277 current = current->prev;
2278 current_y--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00002279 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002280 } else {
Chris Allegrettad865da12002-07-29 23:46:38 +00002281 /* This line is not part of a paragraph. Move down until we get
2282 * to a non "blank" line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002283 do {
2284 /* There is no next paragraph, so nothing to justify. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002285 if (current->next == NULL) {
2286 placewewant = 0;
2287 if (current_y > editwinrows - 4)
2288 edit_update(current, CENTER);
2289 else
2290 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002291 return 0;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002292 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002293 current = current->next;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002294 current_y++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002295 quote_len = quote_length(IFREG(current->data, &qreg));
2296 indent_len = indent_length(current->data + quote_len);
2297 } while (current->data[quote_len + indent_len] == '\0');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002298 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002299/* Now current is the first line of the paragraph, and quote_len
2300 * is the quotation length of that line. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002301
Chris Allegretta6df90f52002-07-19 01:08:59 +00002302/* Next step, compute par_len, the number of lines in this paragraph. */
2303 line = current;
2304 par_len = 1;
2305 indent_len = indent_length(line->data + quote_len);
2306
2307 while (line->next && quotes_match(current->data, quote_len,
2308 IFREG(line->next->data, &qreg))) {
2309 size_t temp_id_len = indent_length(line->next->data + quote_len);
2310
2311 if (!indents_match(line->data + quote_len, indent_len,
2312 line->next->data + quote_len, temp_id_len) ||
2313 line->next->data[quote_len + temp_id_len] == '\0' ||
2314 (quote_len == 0 && temp_id_len > 0
2315#ifndef NANO_SMALL
2316 && !ISSET(AUTOINDENT)
2317#endif
2318 ))
2319 break;
2320 indent_len = temp_id_len;
2321 line = line->next;
2322 par_len++;
2323 }
2324#ifdef HAVE_REGEX_H
2325 /* We no longer need to check quotation. */
2326 regfree(&qreg);
2327#endif
2328/* Now par_len is the number of lines in this paragraph. Should never
2329 * call quotes_match() or quote_length() again. */
2330
2331/* Next step, we loop through the lines of this paragraph, justifying
2332 * each one individually. */
2333 for(; par_len > 0; current_y++, par_len--) {
2334 size_t line_len;
2335 size_t display_len;
2336 /* The width of current in screen columns. */
2337 int break_pos;
2338 /* Where we will break the line. */
2339
2340 indent_len = indent_length(current->data + quote_len) +
2341 quote_len;
2342 /* justify_format() removes excess spaces from the line, and
2343 * changes tabs to spaces. The first argument, 0, means don't
2344 * change the line, just say whether there are changes to be
2345 * made. If there are, we do backup_lines(), which copies the
2346 * original paragraph to the cutbuffer for unjustification, and
2347 * then calls justify_format on the remaining lines. */
2348 if (first_mod_line == NULL &&
2349 justify_format(0, current, indent_len))
2350 first_mod_line = backup_lines(current, par_len, quote_len);
2351
2352 line_len = strlen(current->data);
2353 display_len = strlenpt(current->data);
2354
2355 if (display_len > fill) {
2356 /* The line is too long. Try to wrap it to the next. */
2357 break_pos = break_line(current->data + indent_len,
2358 fill - strnlenpt(current->data, indent_len),
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002359 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002360 if (break_pos == -1 || break_pos + indent_len == line_len)
2361 /* We can't break the line, or don't need to, so just go
2362 * on to the next. */
2363 goto continue_loc;
2364 break_pos += indent_len;
2365 assert(break_pos < line_len);
2366 /* If we haven't backed up the paragraph, do it now. */
2367 if (first_mod_line == NULL)
2368 first_mod_line = backup_lines(current, par_len, quote_len);
2369 if (par_len == 1) {
2370 /* There is no next line in this paragraph. We make a new
2371 * line and copy text after break_pos into it. */
2372 splice_node(current, make_new_node(current),
2373 current->next);
2374 current->next->data = charalloc(indent_len + line_len -
2375 break_pos);
2376 strncpy(current->next->data, current->data,
2377 indent_len);
2378 strcpy(current->next->data + indent_len,
2379 current->data + break_pos + 1);
2380 assert(strlen(current->next->data) ==
2381 indent_len + line_len - break_pos - 1);
2382 totlines++;
2383 totsize += indent_len;
2384 par_len++;
2385 } else {
2386 size_t next_line_len = strlen(current->next->data);
2387
2388 indent_len = quote_len +
2389 indent_length(current->next->data + quote_len);
2390 current->next->data = (char *)nrealloc(current->next->data,
2391 sizeof(char) * (next_line_len + line_len -
2392 break_pos + 1));
2393
2394 memmove(current->next->data + indent_len + line_len - break_pos,
2395 current->next->data + indent_len,
2396 next_line_len - indent_len + 1);
2397 strcpy(current->next->data + indent_len,
2398 current->data + break_pos + 1);
2399 current->next->data[indent_len + line_len - break_pos - 1]
2400 = ' ';
2401#ifndef NANO_SMALL
2402 if (mark_beginbuf == current->next) {
2403 if (mark_beginx < indent_len)
2404 mark_beginx = indent_len;
2405 mark_beginx += line_len - break_pos;
2406 }
2407#endif
2408 }
2409#ifndef NANO_SMALL
2410 if (mark_beginbuf == current && mark_beginx > break_pos) {
2411 mark_beginbuf = current->next;
2412 mark_beginx -= break_pos + 1 - indent_len;
2413 }
2414#endif
2415 null_at(&current->data, break_pos);
2416 current = current->next;
2417 } else if (display_len < fill && par_len > 1) {
2418 size_t next_line_len = strlen(current->next->data);
2419
2420 indent_len = quote_len +
2421 indent_length(current->next->data + quote_len);
2422 break_pos = break_line(current->next->data + indent_len,
2423 fill - display_len - 1, 0);
2424 if (break_pos == -1)
2425 /* We can't pull a word from the next line up to this one,
2426 * so just go on. */
2427 goto continue_loc;
2428
2429 /* If we haven't backed up the paragraph, do it now. */
2430 if (first_mod_line == NULL)
2431 first_mod_line = backup_lines(current, par_len, quote_len);
2432 current->data = (char *)nrealloc(current->data,
2433 line_len + break_pos + 2);
2434 current->data[line_len] = ' ';
2435 strncpy(current->data + line_len + 1,
2436 current->next->data + indent_len, break_pos);
2437 current->data[line_len + break_pos + 1] = '\0';
2438#ifndef NANO_SMALL
2439 if (mark_beginbuf == current->next) {
2440 if (mark_beginx < indent_len + break_pos) {
2441 mark_beginbuf = current;
2442 if (mark_beginx <= indent_len)
2443 mark_beginx = line_len + 1;
2444 else
2445 mark_beginx = line_len + 1 + mark_beginx - indent_len;
2446 } else
2447 mark_beginx -= break_pos + 1;
2448 }
2449#endif
2450 if (indent_len + break_pos == next_line_len) {
2451 line = current->next;
2452 unlink_node(line);
2453 delete_node(line);
2454 totlines--;
2455 totsize -= indent_len;
2456 current_y--;
2457 } else {
2458 memmove(current->next->data + indent_len,
2459 current->next->data + indent_len + break_pos + 1,
2460 next_line_len - break_pos - indent_len);
2461 null_at(&current->next->data,
2462 next_line_len - break_pos);
2463 current = current->next;
2464 }
2465 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002466 continue_loc:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002467 current = current->next;
2468 }
2469/* We are now done justifying the paragraph. There are cleanup things to
2470 * do, and we check for unjustify. */
2471
2472 /* totlines, totsize, and current_y have been maintained above. We
2473 * now set last_par_line to the new end of the paragraph, update
2474 * fileage, set current_x. Also, edit_refresh() needs the line
2475 * numbers to be right, so we renumber(). */
2476 last_par_line = current->prev;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002477 if (first_mod_line != NULL) {
2478 if (first_mod_line->prev == NULL)
2479 fileage = first_mod_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002480 renumber(first_mod_line);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002481 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002482
2483 if (current_y > editwinrows - 4)
2484 edit_update(current, CENTER);
2485 else
2486 edit_refresh();
2487
Chris Allegretta9149e612000-11-27 00:23:41 +00002488 statusbar(_("Can now UnJustify!"));
Chris Allegretta07798352000-11-27 22:58:23 +00002489 /* Change the shortcut list to display the unjustify code */
2490 shortcut_init(1);
2491 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002492 reset_cursor();
2493
Chris Allegretta6df90f52002-07-19 01:08:59 +00002494 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002495 * keystroke and return. */
Chris Allegretta5f071802001-05-06 02:34:31 +00002496
2497#ifndef DISABLE_MOUSE
2498#ifdef NCURSES_MOUSE_VERSION
Chris Allegretta6df90f52002-07-19 01:08:59 +00002499 /* If it was a mouse click, parse it with do_mouse() and it might
2500 * become the unjustify key. Else give it back to the input stream. */
2501 if ((i = wgetch(edit)) == KEY_MOUSE)
Chris Allegretta5f071802001-05-06 02:34:31 +00002502 do_mouse();
2503 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00002504 ungetch(i);
Chris Allegretta5f071802001-05-06 02:34:31 +00002505#endif
2506#endif
2507
Chris Allegretta6df90f52002-07-19 01:08:59 +00002508 if ((i = wgetch(edit)) != NANO_UNJUSTIFY_KEY) {
2509 ungetch(i);
2510 /* Did we back up anything at all? */
2511 if (cutbuffer != cutbuffer_save)
2512 free_filestruct(cutbuffer);
2513 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002514 } else {
Chris Allegretta9149e612000-11-27 00:23:41 +00002515 /* Else restore the justify we just did (ungrateful user!) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002516 current = current_save;
2517 current_x = current_x_save;
2518 current_y = current_y_save;
2519 edittop = edittop_save;
2520 editbot = editbot_save;
2521 if (first_mod_line != NULL) {
2522 filestruct *cutbottom = get_cutbottom();
Chris Allegrettad022eac2000-11-27 02:50:49 +00002523
Chris Allegretta6df90f52002-07-19 01:08:59 +00002524 /* Splice the cutbuffer back into the file. */
2525 cutbottom->next = last_par_line->next;
2526 cutbottom->next->prev = cutbottom;
2527 /* The line numbers after the end of the paragraph have
2528 * been changed, so we change them back. */
2529 renumber(cutbottom->next);
2530 if (first_mod_line->prev != NULL) {
2531 cutbuffer->prev = first_mod_line->prev;
2532 cutbuffer->prev->next = cutbuffer;
2533 } else
2534 fileage = cutbuffer;
2535 cutbuffer = NULL;
2536
2537 last_par_line->next = NULL;
2538 free_filestruct(first_mod_line);
2539
2540 /* Restore global variables from before justify */
2541 totsize = totsize_save;
2542 totlines = filebot->lineno;
2543#ifndef NANO_SMALL
2544 mark_beginbuf = mark_beginbuf_save;
2545 mark_beginx = mark_beginx_save;
2546#endif
2547 flags = flags_save;
2548 if (!ISSET(MODIFIED)) {
2549 titlebar(NULL);
2550 wrefresh(topwin);
2551 }
2552 }
2553 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002554 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002555 cutbuffer = cutbuffer_save;
2556 blank_statusbar_refresh();
2557 /* display shortcut list without UnCut */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002558 shortcut_init(0);
2559 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002560
Chris Allegretta6df90f52002-07-19 01:08:59 +00002561 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002562#endif
2563}
2564
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002565int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002566{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002567 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002568
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002569 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002570
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002571#ifdef ENABLE_MULTIBUFFER
2572 if (!close_open_file()) {
2573 display_main_list();
2574 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002575 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002576 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002577#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002578 finish(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00002579 }
2580
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002581 if (ISSET(TEMP_OPT)) {
2582 i = 1;
2583 } else {
2584 i = do_yesno(0, 0,
2585 _
2586 ("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2587 }
2588
2589#ifdef DEBUG
2590 dump_buffer(fileage);
2591#endif
2592
2593 if (i == 1) {
2594 if (do_writeout(filename, 1, 0) > 0) {
2595
2596#ifdef ENABLE_MULTIBUFFER
2597 if (!close_open_file()) {
2598 display_main_list();
2599 return 1;
2600 }
2601 else
2602#endif
2603 finish(0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002604 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002605 } else if (i == 0) {
2606
2607#ifdef ENABLE_MULTIBUFFER
2608 if (!close_open_file()) {
2609 display_main_list();
2610 return 1;
2611 }
2612 else
2613#endif
2614 finish(0);
2615 } else
2616 statusbar(_("Cancelled"));
2617
2618 display_main_list();
2619 return 1;
2620}
2621
2622void signal_init(void)
2623{
2624#ifdef _POSIX_VDISABLE
2625 struct termios term;
2626#endif
2627
2628 /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */
2629 memset(&act, 0, sizeof(struct sigaction));
2630 act.sa_handler = SIG_IGN;
2631 sigaction(SIGINT, &act, NULL);
2632
2633 /* Trap SIGHUP cuz we want to write the file out. */
2634 act.sa_handler = handle_hup;
2635 sigaction(SIGHUP, &act, NULL);
2636
2637#ifndef NANO_SMALL
2638 act.sa_handler = handle_sigwinch;
2639 sigaction(SIGWINCH, &act, NULL);
2640#endif
2641
2642#ifdef _POSIX_VDISABLE
2643 tcgetattr(0, &term);
2644
Chris Allegrettae42df732002-10-15 00:27:55 +00002645 /* Ignore ^s, much to Chris' chagrin */
2646 term.c_cc[VSTOP] = _POSIX_VDISABLE;
2647
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002648#ifdef VDSUSP
2649 term.c_cc[VDSUSP] = _POSIX_VDISABLE;
2650#endif /* VDSUSP */
2651
2652#endif /* _POSIX_VDISABLE */
2653
2654 if (!ISSET(SUSPEND)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002655 /* Insane! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002656#ifdef _POSIX_VDISABLE
2657 term.c_cc[VSUSP] = _POSIX_VDISABLE;
2658#else
2659 act.sa_handler = SIG_IGN;
2660 sigaction(SIGTSTP, &act, NULL);
2661#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002662 } else {
2663 /* If we don't do this, it seems other stuff interrupts the
2664 suspend handler! Try using nano with mutt without this
2665 line. */
2666 sigfillset(&act.sa_mask);
2667
2668 act.sa_handler = do_suspend;
2669 sigaction(SIGTSTP, &act, NULL);
2670
2671 act.sa_handler = do_cont;
2672 sigaction(SIGCONT, &act, NULL);
2673 }
2674
2675#ifdef _POSIX_VDISABLE
2676 tcsetattr(0, TCSANOW, &term);
2677#endif
2678}
2679
2680/* Handler for SIGHUP */
2681RETSIGTYPE handle_hup(int signal)
2682{
2683 die(_("Received SIGHUP"));
2684}
2685
2686/* What do we do when we catch the suspend signal */
2687RETSIGTYPE do_suspend(int signal)
2688{
2689 endwin();
2690 printf("\n\n\n\n\nUse \"fg\" to return to nano\n");
2691 fflush(stdout);
2692
2693 /* Restore the terminal settings for the disabled keys */
2694 tcsetattr(0, TCSANOW, &oldterm);
2695
2696 /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but
2697 then we could be (and were) interrupted in the middle of the call.
2698 So we do it the mutt way instead */
2699 kill(0, SIGSTOP);
2700}
2701
2702/* Restore the suspend handler when we come back into the prog */
2703RETSIGTYPE do_cont(int signal)
2704{
2705 /* Now we just update the screen instead of having to reenable the
2706 SIGTSTP handler. */
2707
2708 doupdate();
2709 /* The Hurd seems to need this, otherwise a ^Y after a ^Z will
2710 start suspending again. */
2711 signal_init();
2712
2713#ifndef NANO_SMALL
2714 /* Perhaps the user resized the window while we slept. */
2715 handle_sigwinch(0);
2716#endif
2717}
2718
2719#ifndef NANO_SMALL
2720void handle_sigwinch(int s)
2721{
2722 const char *tty = ttyname(0);
2723 int fd;
2724 int result = 0;
2725 struct winsize win;
2726
2727 if (!tty)
2728 return;
2729 fd = open(tty, O_RDWR);
2730 if (fd == -1)
2731 return;
2732 result = ioctl(fd, TIOCGWINSZ, &win);
2733 close(fd);
2734 if (result == -1)
2735 return;
2736
2737 /* Could check whether the COLS or LINES changed, and return
2738 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2739 * variables, and in some cases ncurses has already updated them.
2740 * But not in all cases, argh. */
2741 COLS = win.ws_col;
2742 LINES = win.ws_row;
2743 if ((editwinrows = LINES - 5 + no_help()) < MIN_EDITOR_ROWS)
2744 die_too_small();
2745
2746#ifndef DISABLE_WRAPJUSTIFY
2747 fill = wrap_at;
2748 if (fill <= 0)
2749 fill += COLS;
2750 if (fill < MIN_FILL_LENGTH)
2751 die_too_small();
2752#endif
2753
2754 hblank = nrealloc(hblank, COLS + 1);
2755 memset(hblank, ' ', COLS);
2756 hblank[COLS] = '\0';
2757
2758#ifdef HAVE_RESIZETERM
2759 resizeterm(LINES, COLS);
2760#ifdef HAVE_WRESIZE
2761 if (wresize(topwin, 2, COLS) == ERR)
2762 die(_("Cannot resize top win"));
2763 if (mvwin(topwin, 0, 0) == ERR)
2764 die(_("Cannot move top win"));
2765 if (wresize(edit, editwinrows, COLS) == ERR)
2766 die(_("Cannot resize edit win"));
2767 if (mvwin(edit, 2, 0) == ERR)
2768 die(_("Cannot move edit win"));
2769 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
2770 die(_("Cannot resize bottom win"));
2771 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
2772 die(_("Cannot move bottom win"));
2773#endif /* HAVE_WRESIZE */
2774#endif /* HAVE_RESIZETERM */
2775
2776 fix_editbot();
2777
2778 if (current_y > editwinrows - 1)
2779 edit_update(editbot, CENTER);
2780 erase();
2781
2782 /* Do these b/c width may have changed... */
2783 refresh();
2784 titlebar(NULL);
2785 edit_refresh();
2786 display_main_list();
2787 blank_statusbar();
2788 total_refresh();
2789
2790 /* Turn cursor back on for sure */
2791 curs_set(1);
2792
2793 /* Jump back to main loop */
2794 siglongjmp(jmpbuf, 1);
2795}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002796#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002797
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002798/* If the NumLock key has made the keypad go awry, print an error
2799 message; hopefully we can address it later. */
2800void print_numlock_warning(void)
2801{
2802 static int didmsg = 0;
2803 if (!didmsg) {
2804 statusbar(_
2805 ("NumLock glitch detected. Keypad will malfunction with NumLock off"));
2806 didmsg = 1;
2807 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002808}
2809
Chris Allegrettadab017e2002-04-23 10:56:06 +00002810#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002811void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002812{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002813 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002814
Chris Allegretta658399a2001-06-14 02:54:22 +00002815 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002816 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002817
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002818 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002819 case TOGGLE_PICOMODE_KEY:
Chris Allegretta07798352000-11-27 22:58:23 +00002820 shortcut_init(0);
Chris Allegrettac1049ac2001-08-17 00:03:46 +00002821 SET(CLEAR_BACKUPSTRING);
Chris Allegretta756f2202000-09-01 13:32:47 +00002822 display_main_list();
2823 break;
2824 case TOGGLE_SUSPEND_KEY:
2825 signal_init();
2826 break;
2827 case TOGGLE_MOUSE_KEY:
2828 mouse_init();
2829 break;
2830 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00002831 wclear(bottomwin);
2832 wrefresh(bottomwin);
2833 window_init();
Chris Allegrettaaffeda82000-12-18 04:03:48 +00002834 fix_editbot();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002835 edit_refresh();
2836 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002837 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002838 case TOGGLE_DOS_KEY:
2839 UNSET(MAC_FILE);
2840 break;
2841 case TOGGLE_MAC_KEY:
2842 UNSET(DOS_FILE);
2843 break;
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002844 case TOGGLE_SYNTAX_KEY:
2845 edit_refresh();
2846 break;
Chris Allegretta756f2202000-09-01 13:32:47 +00002847 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002848
Chris Allegretta6df90f52002-07-19 01:08:59 +00002849 /* We are assuming here that shortcut_init() above didn't free and
2850 * reallocate the toggles. */
2851 enabled = ISSET(which->flag);
2852 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2853 enabled = !enabled;
2854 statusbar("%s %s", which->desc,
2855 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002856}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002857#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002858
Chris Allegretta1748cd12001-01-13 17:22:54 +00002859/* This function returns the correct keystroke, given the A,B,C or D
2860 input key. This is a common sequence of many terms which send
2861 Esc-O-[A-D] or Esc-[-[A-D]. */
2862int ABCD(int input)
2863{
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002864 switch (input) {
2865 case 'A':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002866 case 'a':
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002867 return (KEY_UP);
2868 case 'B':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002869 case 'b':
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002870 return (KEY_DOWN);
2871 case 'C':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002872 case 'c':
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002873 return (KEY_RIGHT);
2874 case 'D':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002875 case 'd':
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002876 return (KEY_LEFT);
2877 default:
2878 return 0;
Chris Allegretta1748cd12001-01-13 17:22:54 +00002879 }
2880}
2881
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002882int main(int argc, char *argv[])
2883{
2884 int optchr;
2885 int kbinput; /* Input from keyboard */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00002886 int startline = 0; /* Line to try and start at */
Chris Allegretta08020882001-01-29 23:37:54 +00002887 int keyhandled; /* Have we handled the keystroke yet? */
Chris Allegretta9caa1932002-02-15 20:08:05 +00002888 int modify_control_seq;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002889 const char *argv0;
2890 const shortcut *s;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00002891#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00002892 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00002893#endif
Chris Allegretta0357c4d2001-09-19 02:59:25 +00002894
Chris Allegretta9b4055c2002-03-29 16:00:59 +00002895#ifdef _POSIX_VDISABLE
2896 struct termios term;
2897#endif
2898
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002899#ifdef HAVE_GETOPT_LONG
2900 int option_index = 0;
2901 struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002902 {"help", 0, 0, 'h'},
2903#ifdef ENABLE_MULTIBUFFER
2904 {"multibuffer", 0, 0, 'F'},
2905#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002906#ifdef ENABLE_NANORC
2907 {"ignorercfiles", 0, 0, 'I'},
2908#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002909 {"keypad", 0, 0, 'K'},
2910#ifndef DISABLE_JUSTIFY
2911 {"quotestr", 1, 0, 'Q'},
2912#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00002913#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002914 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00002915#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002916 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002917 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002918#ifdef ENABLE_COLOR
2919 {"syntax", 1, 0, 'Y'},
2920#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002921 {"const", 0, 0, 'c'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002922 {"nofollow", 0, 0, 'l'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002923 {"mouse", 0, 0, 'm'},
Chris Allegrettae1f14522001-09-19 03:19:43 +00002924#ifndef DISABLE_OPERATINGDIR
2925 {"operatingdir", 1, 0, 'o'},
2926#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002927 {"pico", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002928#ifndef DISABLE_WRAPJUSTIFY
2929 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002930#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002931#ifndef DISABLE_SPELLER
2932 {"speller", 1, 0, 's'},
2933#endif
2934 {"tempfile", 0, 0, 't'},
2935 {"view", 0, 0, 'v'},
2936 {"nowrap", 0, 0, 'w'},
2937 {"nohelp", 0, 0, 'x'},
2938 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00002939#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002940 {"backup", 0, 0, 'B'},
2941 {"dos", 0, 0, 'D'},
2942 {"mac", 0, 0, 'M'},
2943 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00002944 {"smooth", 0, 0, 'S'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002945 {"autoindent", 0, 0, 'i'},
2946 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00002947#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002948 {0, 0, 0, 0}
2949 };
2950#endif
2951
2952 /* Flag inits... */
2953 SET(FOLLOW_SYMLINKS);
2954
2955#ifndef NANO_SMALL
Chris Allegretta8bc03b62001-02-09 02:57:52 +00002956#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002957 setlocale(LC_ALL, "");
2958 bindtextdomain(PACKAGE, LOCALEDIR);
2959 textdomain(PACKAGE);
2960#endif
Chris Allegretta8bc03b62001-02-09 02:57:52 +00002961#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002962
Chris Allegretta8d8e0122001-04-18 04:28:54 +00002963#ifdef ENABLE_NANORC
Chris Allegretta1c5c3382002-07-23 00:33:07 +00002964 {
2965 /* scan through the options and handle -I/--ignorercfiles
2966 first, so that it's handled before we call do_rcfile() and
2967 read the other options; don't use getopt()/getopt_long()
2968 here, because there's no way to reset it properly
2969 afterward */
2970 int i;
2971 for (i = 1; i < argc; i++) {
2972 if (!strcmp(argv[i], "--"))
2973 break;
2974 else if (!strcmp(argv[i], "-I"))
2975 SET(NO_RCFILE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002976#ifdef HAVE_GETOPT_LONG
Chris Allegretta1c5c3382002-07-23 00:33:07 +00002977 else if (!strcmp(argv[i], "--ignorercfiles"))
2978 SET(NO_RCFILE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002979#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002980 }
2981 }
Chris Allegretta1c5c3382002-07-23 00:33:07 +00002982 if (!ISSET(NO_RCFILE))
2983 do_rcfile();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002984#endif /* ENABLE_NANORC */
2985
2986#ifdef HAVE_GETOPT_LONG
2987 while ((optchr = getopt_long(argc, argv, "h?BDFIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz",
2988 long_options, &option_index)) != EOF) {
2989#else
2990 while ((optchr =
2991 getopt(argc, argv, "h?BDFIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz")) != EOF) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002992#endif
2993
2994 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002995
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002996 case 'h':
2997 case '?':
2998 usage();
2999 exit(0);
3000 case 'a':
3001 case 'b':
3002 case 'e':
3003 case 'f':
3004 case 'g':
3005 case 'j':
3006 /* Pico compatibility flags */
3007 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003008#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003009 case 'B':
3010 SET(BACKUP_FILE);
3011 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003012 case 'D':
3013 SET(DOS_FILE);
3014 break;
3015#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003016#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003017 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003018 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003019 break;
3020#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003021#ifdef ENABLE_NANORC
Chris Allegretta6df90f52002-07-19 01:08:59 +00003022 case 'I':
3023 break;
3024#endif
Chris Allegretta48bd3782002-01-03 21:26:34 +00003025 case 'K':
3026 SET(ALT_KEYPAD);
3027 break;
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003028#ifndef NANO_SMALL
3029 case 'M':
3030 SET(MAC_FILE);
3031 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003032 case 'N':
3033 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003034 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003035#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003036 case 'Q':
3037#ifndef DISABLE_JUSTIFY
3038 quotestr = optarg;
3039 break;
3040#else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003041 usage();
3042 exit(1);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003043#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003044#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003045 case 'R':
3046 SET(USE_REGEXP);
3047 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003048#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003049#ifndef NANO_SMALL
3050 case 'S':
3051 SET(SMOOTHSCROLL);
3052 break;
3053#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003054 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003055 {
3056 int i;
3057 char *first_error;
3058
3059 /* Using strtol instead of atoi lets us accept 0 while
3060 * checking other errors. */
3061 i = (int)strtol(optarg, &first_error, 10);
3062 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0') {
3063 usage();
3064 exit(1);
3065 } else
3066 tabsize = i;
3067 if (tabsize <= 0) {
3068 fprintf(stderr, _("Tab size is too small for nano...\n"));
3069 exit(1);
3070 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003071 }
3072 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003073 case 'V':
3074 version();
3075 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003076#ifdef ENABLE_COLOR
3077 case 'Y':
3078 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3079 break;
3080#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003081 case 'c':
3082 SET(CONSTUPDATE);
3083 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003084#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003085 case 'i':
3086 SET(AUTOINDENT);
3087 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003088 case 'k':
3089 SET(CUT_TO_END);
3090 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003091#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003092 case 'l':
3093 UNSET(FOLLOW_SYMLINKS);
3094 break;
3095 case 'm':
3096 SET(USE_MOUSE);
3097 break;
Chris Allegrettae1f14522001-09-19 03:19:43 +00003098#ifndef DISABLE_OPERATINGDIR
3099 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003100 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003101 break;
3102#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003103 case 'p':
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +00003104 SET(PICO_MODE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003105 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003106#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003107 case 'r':
3108 {
3109 int i;
3110 char *first_error;
3111
3112 /* Using strtol instead of atoi lets us accept 0 while
3113 * checking other errors. */
3114 i = (int)strtol(optarg, &first_error, 10);
3115 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0') {
3116 usage();
3117 exit(1);
3118 } else
3119 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003120 }
3121 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003122#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003123#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003124 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003125 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003126 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003127#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003128 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003129 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003130 break;
3131 case 'v':
3132 SET(VIEW_MODE);
3133 break;
3134 case 'w':
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00003135#ifdef DISABLE_WRAPPING
3136 usage();
3137 exit(0);
3138#else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003139 SET(NO_WRAP);
3140 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003141#endif /* DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003142 case 'x':
3143 SET(NO_HELP);
3144 break;
3145 case 'z':
3146 SET(SUSPEND);
3147 break;
3148 default:
3149 usage();
Chris Allegretta4da1fc62000-06-21 03:00:43 +00003150 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003151 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003152 }
3153
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003154#ifndef DISABLE_OPERATINGDIR
3155 /* Set up the operating directory. This entails chdir()ing there, so
3156 that file reads and writes will be based there. */
3157 init_operating_dir();
3158#endif
3159
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003160 /* Clear the filename we'll be using */
3161 filename = charalloc(1);
3162 filename[0] = '\0';
3163
3164 /* See if we were invoked with the name "pico" */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003165 argv0 = strrchr(argv[0], '/');
3166 if ((argv0 && strstr(argv0, "pico"))
3167 || (!argv0 && strstr(argv[0], "pico")))
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +00003168 SET(PICO_MODE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003169
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003170 /* See if there's a non-option in argv (first non-option is the
3171 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003172 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003173 /* Look for the +line flag... */
3174 if (argv[optind][0] == '+') {
3175 startline = atoi(&argv[optind][1]);
3176 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003177 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003178 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003179 } else
3180 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003181 }
3182
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003183 /* First back up the old settings so they can be restored, duh */
3184 tcgetattr(0, &oldterm);
3185
3186#ifdef _POSIX_VDISABLE
3187 term = oldterm;
3188 term.c_cc[VINTR] = _POSIX_VDISABLE;
3189 term.c_cc[VQUIT] = _POSIX_VDISABLE;
3190 term.c_lflag &= ~IEXTEN;
3191 tcsetattr(0, TCSANOW, &term);
3192#endif
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003193
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003194 /* now ncurses init stuff... */
3195 initscr();
3196 savetty();
3197 nonl();
3198 cbreak();
3199 noecho();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003200
3201 /* Set up some global variables */
Chris Allegretta56214c62001-09-27 02:46:53 +00003202 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003203 shortcut_init(0);
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003204 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003205
3206#ifdef DEBUG
3207 fprintf(stderr, _("Main: set up windows\n"));
3208#endif
3209
Chris Allegretta2a42af12000-09-12 23:02:49 +00003210 window_init();
Chris Allegretta756f2202000-09-01 13:32:47 +00003211 mouse_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003212
Chris Allegretta48bd3782002-01-03 21:26:34 +00003213 if (!ISSET(ALT_KEYPAD)) {
3214 keypad(edit, TRUE);
3215 keypad(bottomwin, TRUE);
3216 }
3217
Chris Allegretta08893e02001-11-29 02:42:27 +00003218#ifdef ENABLE_COLOR
3219 do_colorinit();
Chris Allegretta08893e02001-11-29 02:42:27 +00003220#endif /* ENABLE_COLOR */
3221
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003222#ifdef DEBUG
3223 fprintf(stderr, _("Main: bottom win\n"));
3224#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003225 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003226 display_main_list();
3227
3228#ifdef DEBUG
3229 fprintf(stderr, _("Main: open file\n"));
3230#endif
3231
Chris Allegretta31c76662000-11-21 06:20:20 +00003232 /* Now we check to see if argv[optind] is non-null to determine if
3233 we're dealing with a new file or not, not argc == 1... */
3234 if (argv[optind] == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003235 new_file();
3236 else
3237 open_file(filename, 0, 0);
3238
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003239 titlebar(NULL);
3240
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003241 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003242 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003243 else
Chris Allegretta234a34d2000-07-29 04:33:38 +00003244 edit_update(fileage, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003245
Chris Allegretta08020882001-01-29 23:37:54 +00003246 /* return here after a sigwinch */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003247 sigsetjmp(jmpbuf, 1);
Chris Allegretta08020882001-01-29 23:37:54 +00003248
3249 /* Fix clobber-age */
3250 kbinput = 0;
3251 keyhandled = 0;
3252 modify_control_seq = 0;
3253
Robert Siemborski6967eec2000-07-08 14:23:32 +00003254 edit_refresh();
3255 reset_cursor();
3256
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003257 while (1) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003258
Chris Allegretta6fe61492001-05-21 12:56:25 +00003259#ifndef DISABLE_MOUSE
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003260 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003261#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003262
Chris Allegretta9239d742000-09-06 15:19:18 +00003263#ifndef _POSIX_VDISABLE
3264 /* We're going to have to do it the old way, i.e. on cygwin */
3265 raw();
3266#endif
3267
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003268 kbinput = wgetch(edit);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003269#ifdef DEBUG
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003270 fprintf(stderr, _("AHA! %c (%d)\n"), kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003271#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003272 if (kbinput == 27) { /* Grab Alt-key stuff first */
3273 switch (kbinput = wgetch(edit)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003274 /* Alt-O, suddenly very important ;) */
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003275 case 'O':
Chris Allegretta16e41682000-09-11 22:33:54 +00003276 kbinput = wgetch(edit);
Chris Allegretta316e4d92001-04-28 16:31:19 +00003277 if ((kbinput <= 'D' && kbinput >= 'A') ||
3278 (kbinput <= 'd' && kbinput >= 'a'))
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003279 kbinput = ABCD(kbinput);
Chris Allegretta201d9bf2001-01-14 03:17:53 +00003280 else if (kbinput <= 'z' && kbinput >= 'j')
3281 print_numlock_warning();
3282 else if (kbinput <= 'S' && kbinput >= 'P')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003283 kbinput = KEY_F(kbinput - 79);
Chris Allegretta16e41682000-09-11 22:33:54 +00003284#ifdef DEBUG
3285 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003286 fprintf(stderr, _("I got Alt-O-%c! (%d)\n"),
3287 kbinput, kbinput);
3288 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003289 }
3290#endif
3291 break;
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003292 case 27:
3293 /* If we get Alt-Alt, the next keystroke should be the same as a
3294 control sequence */
3295 modify_control_seq = 1;
3296 keyhandled = 1;
3297 break;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003298 case '[':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003299 switch (kbinput = wgetch(edit)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003300 case '1': /* Alt-[-1-[0-5,7-9] = F1-F8 in X at least */
Chris Allegretta16e41682000-09-11 22:33:54 +00003301 kbinput = wgetch(edit);
3302 if (kbinput >= '1' && kbinput <= '5') {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003303 kbinput = KEY_F(kbinput - 48);
3304 wgetch(edit);
3305 } else if (kbinput >= '7' && kbinput <= '9') {
3306 kbinput = KEY_F(kbinput - 49);
3307 wgetch(edit);
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003308 } else if (kbinput == '~')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003309 kbinput = KEY_HOME;
Chris Allegretta16e41682000-09-11 22:33:54 +00003310#ifdef DEBUG
3311 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003312 fprintf(stderr, _("I got Alt-[-1-%c! (%d)\n"),
3313 kbinput, kbinput);
3314 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003315 }
3316#endif
Chris Allegretta16e41682000-09-11 22:33:54 +00003317 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003318 case '2': /* Alt-[-2-[0,1,3,4] = F9-F12 in many terms */
Chris Allegretta16e41682000-09-11 22:33:54 +00003319 kbinput = wgetch(edit);
Chris Allegretta16e41682000-09-11 22:33:54 +00003320 switch (kbinput) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003321 case '0':
3322 kbinput = KEY_F(9);
3323 wgetch(edit);
3324 break;
3325 case '1':
3326 kbinput = KEY_F(10);
3327 wgetch(edit);
3328 break;
3329 case '3':
3330 kbinput = KEY_F(11);
3331 wgetch(edit);
3332 break;
3333 case '4':
3334 kbinput = KEY_F(12);
3335 wgetch(edit);
3336 break;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003337 case '~':
3338 goto do_insertkey;
Chris Allegretta16e41682000-09-11 22:33:54 +00003339#ifdef DEBUG
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003340 default:
3341 fprintf(stderr, _("I got Alt-[-2-%c! (%d)\n"),
3342 kbinput, kbinput);
3343 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003344#endif
Chris Allegretta16e41682000-09-11 22:33:54 +00003345 }
3346 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003347 case '3': /* Alt-[-3 = Delete? */
Chris Allegretta16e41682000-09-11 22:33:54 +00003348 kbinput = NANO_DELETE_KEY;
3349 wgetch(edit);
3350 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003351 case '4': /* Alt-[-4 = End? */
Chris Allegretta16e41682000-09-11 22:33:54 +00003352 kbinput = NANO_END_KEY;
3353 wgetch(edit);
3354 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003355 case '5': /* Alt-[-5 = Page Up */
Chris Allegretta16e41682000-09-11 22:33:54 +00003356 kbinput = KEY_PPAGE;
3357 wgetch(edit);
3358 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003359 case 'V': /* Alt-[-V = Page Up in Hurd Console */
Chris Allegretta7bf72742001-10-28 04:29:55 +00003360 case 'I': /* Alt-[-I = Page Up - FreeBSD Console */
3361 kbinput = KEY_PPAGE;
3362 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003363 case '6': /* Alt-[-6 = Page Down */
Chris Allegretta16e41682000-09-11 22:33:54 +00003364 kbinput = KEY_NPAGE;
3365 wgetch(edit);
3366 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003367 case 'U': /* Alt-[-U = Page Down in Hurd Console */
Chris Allegretta7bf72742001-10-28 04:29:55 +00003368 case 'G': /* Alt-[-G = Page Down - FreeBSD Console */
3369 kbinput = KEY_NPAGE;
3370 break;
Chris Allegrettab26ecb52001-07-04 16:27:05 +00003371 case '7':
3372 kbinput = KEY_HOME;
3373 wgetch(edit);
3374 break;
3375 case '8':
3376 kbinput = KEY_END;
3377 wgetch(edit);
3378 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003379 case '9': /* Alt-[-9 = Delete in Hurd Console */
3380 kbinput = KEY_DC;
3381 break;
Chris Allegretta32da4562002-01-02 15:12:21 +00003382 case '@': /* Alt-[-@ = Insert in Hurd Console */
3383 case 'L': /* Alt-[-L = Insert - FreeBSD Console */
3384 goto do_insertkey;
3385 case '[': /* Alt-[-[-[A-E], F1-F5 in Linux console */
Chris Allegretta16e41682000-09-11 22:33:54 +00003386 kbinput = wgetch(edit);
Chris Allegrettab26ecb52001-07-04 16:27:05 +00003387 if (kbinput >= 'A' && kbinput <= 'E')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003388 kbinput = KEY_F(kbinput - 64);
Chris Allegretta16e41682000-09-11 22:33:54 +00003389 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003390 case 'A':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003391 case 'B':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003392 case 'C':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003393 case 'D':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003394 case 'a':
3395 case 'b':
3396 case 'c':
3397 case 'd':
Chris Allegretta1748cd12001-01-13 17:22:54 +00003398 kbinput = ABCD(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003399 break;
3400 case 'H':
3401 kbinput = KEY_HOME;
3402 break;
3403 case 'F':
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003404 case 'Y': /* End Key in Hurd Console */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003405 kbinput = KEY_END;
3406 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003407 default:
3408#ifdef DEBUG
3409 fprintf(stderr, _("I got Alt-[-%c! (%d)\n"),
3410 kbinput, kbinput);
3411#endif
3412 break;
3413 }
3414 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003415
Chris Allegretta355fbe52001-07-14 19:32:47 +00003416#ifdef ENABLE_MULTIBUFFER
Chris Allegretta819e3db2001-07-11 02:37:19 +00003417 case NANO_OPENPREV_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003418 case NANO_OPENPREV_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003419 open_prevfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003420 keyhandled = 1;
3421 break;
3422 case NANO_OPENNEXT_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003423 case NANO_OPENNEXT_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003424 open_nextfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003425 keyhandled = 1;
3426 break;
Chris Allegretta9cf9e062001-07-11 12:06:13 +00003427#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003428 default:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003429 /* Check for the altkey defs.... */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003430 for (s = main_list; s != NULL; s = s->next)
3431 if (kbinput == s->altval ||
Chris Allegretta6232d662002-05-12 19:52:15 +00003432 kbinput == s->altval - 32) {
3433 if (ISSET(VIEW_MODE) && !s->viewok)
3434 print_view_warning();
3435 else
3436 s->func();
3437 keyhandled = 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003438 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003439 }
Chris Allegretta756f2202000-09-01 13:32:47 +00003440#ifndef NANO_SMALL
3441 /* And for toggle switches */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003442 for (t = toggles; t != NULL && !keyhandled; t = t->next)
3443 if (kbinput == t->val ||
3444 (t->val > 'a' &&
3445 kbinput == t->val - 32)) {
3446 do_toggle(t);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003447 keyhandled = 1;
3448 break;
Chris Allegretta756f2202000-09-01 13:32:47 +00003449 }
3450#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003451#ifdef DEBUG
3452 fprintf(stderr, _("I got Alt-%c! (%d)\n"), kbinput,
3453 kbinput);
3454#endif
3455 break;
3456 }
3457 }
Chris Allegrettacf287c82002-07-20 13:57:41 +00003458 /* If modify_control_seq is set, we received an Alt-Alt
3459 sequence before this, so we make this key a control sequence
3460 by subtracting 32, 64, or 96, depending on its value. */
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003461 if (!keyhandled && modify_control_seq) {
Chris Allegrettacf287c82002-07-20 13:57:41 +00003462 if (kbinput == ' ')
3463 kbinput -= 32;
3464 else if (kbinput >= 'A' && kbinput < 'a')
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003465 kbinput -= 64;
3466 else if (kbinput >= 'a' && kbinput <= 'z')
3467 kbinput -= 96;
3468
3469 modify_control_seq = 0;
3470 }
3471
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003472 /* Look through the main shortcut list to see if we've hit a
3473 shortcut key */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003474
Chris Allegrettaf5de33a2002-02-27 04:14:16 +00003475#if !defined(DISABLE_BROWSER) || !defined(DISABLE_MOUSE) || !defined (DISABLE_HELP)
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003476 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
Chris Allegrettaf5de33a2002-02-27 04:14:16 +00003477#else
3478 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
3479#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003480 if (kbinput == s->val ||
3481 (s->misc1 && kbinput == s->misc1) ||
3482 (s->misc2 && kbinput == s->misc2)) {
3483 if (ISSET(VIEW_MODE) && !s->viewok)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003484 print_view_warning();
3485 else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003486 s->func();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003487 keyhandled = 1;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003488 /* rarely, the value of s can change after s->func(),
3489 leading to problems; get around this by breaking out
3490 explicitly once we successfully handle a shortcut */
3491 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003492 }
3493 }
Chris Allegrettae42df732002-10-15 00:27:55 +00003494
3495#ifdef _POSIX_VDISABLE
3496 /* Don't even think about changing this string */
3497 if (kbinput == 19)
3498 statusbar(_("XOFF ignored, mumble mumble."));
3499#endif
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003500 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3501 Control-S and Control-Q */
Chris Allegretta9239d742000-09-06 15:19:18 +00003502 if (kbinput == 17 || kbinput == 19)
3503 keyhandled = 1;
3504
Chris Allegretta9caa1932002-02-15 20:08:05 +00003505 /* Catch ^Z by hand when triggered also
3506 407 == ^Z in Linux console when keypad() is used? */
3507 if (kbinput == 26 || kbinput == 407) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003508 if (ISSET(SUSPEND))
3509 do_suspend(0);
3510 keyhandled = 1;
3511 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003512
Chris Allegretta1c27d3e2001-10-02 02:56:45 +00003513#ifndef USE_SLANG
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003514 /* Hack, make insert key do something useful, like insert file */
3515 if (kbinput == KEY_IC) {
Chris Allegretta1c27d3e2001-10-02 02:56:45 +00003516#else
3517 if (0) {
3518#endif
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003519 do_insertkey:
3520
3521#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +00003522 /* do_insertfile_void() contains the logic needed to
3523 handle view mode with the view mode/multibuffer
3524 exception, so use it here */
3525 do_insertfile_void();
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003526#else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003527 if (!ISSET(VIEW_MODE))
3528 do_insertfile_void();
3529 else
3530 print_view_warning();
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003531#endif
3532
Chris Allegretta1c27d3e2001-10-02 02:56:45 +00003533 keyhandled = 1;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003534 }
3535
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003536 /* Last gasp, stuff that's not in the main lists */
3537 if (!keyhandled)
3538 switch (kbinput) {
Chris Allegretta84de5522001-04-12 14:51:48 +00003539#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003540#ifdef NCURSES_MOUSE_VERSION
3541 case KEY_MOUSE:
3542 do_mouse();
3543 break;
3544#endif
3545#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003546
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003547 case 0: /* Erg */
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003548 case -1: /* Stuff that we don't want to do squat */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003549 case 410: /* Must ignore this, it gets sent when we resize */
Chris Allegrettab3655b42001-10-22 03:15:31 +00003550 case 29: /* Ctrl-] */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003551#ifdef PDCURSES
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003552 case 541: /* ???? */
3553 case 542: /* Control and alt in Windows *shrug* */
Chris Allegretta72623582000-11-29 23:43:28 +00003554 case 543: /* Right ctrl key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003555 case 544:
Chris Allegretta72623582000-11-29 23:43:28 +00003556 case 545: /* Right alt key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003557#endif
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003558
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003559 break;
3560 default:
3561#ifdef DEBUG
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003562 fprintf(stderr, _("I got %c (%d)!\n"), kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003563#endif
3564 /* We no longer stop unhandled sequences so that people with
3565 odd character sets can type... */
3566
3567 if (ISSET(VIEW_MODE)) {
3568 print_view_warning();
3569 break;
3570 }
3571 do_char(kbinput);
3572 }
Chris Allegretta7fdbd052001-10-02 00:55:38 +00003573 if (ISSET(DISABLE_CURPOS))
3574 UNSET(DISABLE_CURPOS);
3575 else if (ISSET(CONSTUPDATE))
Chris Allegretta2084acc2001-11-29 03:43:08 +00003576 do_cursorpos(1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003577
3578 reset_cursor();
3579 wrefresh(edit);
3580 keyhandled = 0;
3581 }
3582
3583 getchar();
3584 finish(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003585}