blob: ddc57c0c1229b38d6669fde0ef8449521b275e23 [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002/**************************************************************************
3 * nano.c *
4 * *
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +00005 * Copyright (C) 1999-2004 Chris Allegretta *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00006 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
Chris Allegretta3a24f3f2001-10-24 11:33:54 +00008 * the Free Software Foundation; either version 2, or (at your option) *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00009 * any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 * *
20 **************************************************************************/
21
Chris Allegretta6efda542001-04-28 18:03:52 +000022#include "config.h"
23
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000024#include <stdio.h>
25#include <stdlib.h>
26#include <stdarg.h>
27#include <signal.h>
Chris Allegretta08020882001-01-29 23:37:54 +000028#include <setjmp.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000029#include <unistd.h>
30#include <string.h>
31#include <fcntl.h>
32#include <sys/stat.h>
33#include <sys/ioctl.h>
34#include <sys/param.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000035#include <sys/types.h>
36#include <sys/wait.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000037#include <errno.h>
38#include <ctype.h>
39#include <locale.h>
40#include <limits.h>
Adam Rogoyski77f36de2000-06-07 03:56:54 +000041#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000042#include "proto.h"
43#include "nano.h"
44
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000045#ifdef HAVE_TERMIOS_H
46#include <termios.h>
47#endif
48
49#ifdef HAVE_TERMIO_H
50#include <termio.h>
51#endif
52
53#ifdef HAVE_GETOPT_H
54#include <getopt.h>
55#endif
56
Chris Allegretta6fe61492001-05-21 12:56:25 +000057#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +000058static int fill = 0; /* Fill - where to wrap lines, basically */
Chris Allegretta6fe61492001-05-21 12:56:25 +000059#endif
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000060#ifndef DISABLE_WRAPPING
61static int same_line_wrap = 0; /* Whether wrapped text should be
62 prepended to the next line */
63#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000064
Chris Allegretta6df90f52002-07-19 01:08:59 +000065static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000066static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000067
Chris Allegretta08020882001-01-29 23:37:54 +000068static sigjmp_buf jmpbuf; /* Used to return to mainloop after SIGWINCH */
69
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000070/* What we do when we're all set to exit */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +000071RETSIGTYPE finish(int sigage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000072{
73 if (!ISSET(NO_HELP)) {
74 mvwaddstr(bottomwin, 1, 0, hblank);
75 mvwaddstr(bottomwin, 2, 0, hblank);
Chris Allegretta4da1fc62000-06-21 03:00:43 +000076 } else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000077 mvwaddstr(bottomwin, 0, 0, hblank);
Chris Allegretta6b58acd2001-04-12 03:01:53 +000078
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000079 wrefresh(bottomwin);
80 endwin();
81
82 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000083 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000084
Chris Allegrettad8451932003-03-11 03:50:40 +000085#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
86 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
87 save_history();
88#endif
89
Chris Allegretta6232d662002-05-12 19:52:15 +000090#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000091 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +000092#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000093
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000094 exit(sigage);
95}
96
97/* Die (gracefully?) */
Chris Allegretta6df90f52002-07-19 01:08:59 +000098void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000099{
100 va_list ap;
101
Chris Allegrettaa0d89972003-02-03 03:32:08 +0000102 endwin();
103 curses_ended = TRUE;
104
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000105 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000106 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000107
Chris Allegretta6df90f52002-07-19 01:08:59 +0000108 va_start(ap, msg);
109 vfprintf(stderr, msg, ap);
110 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000111
Chris Allegretta32da4562002-01-02 15:12:21 +0000112 /* save the currently loaded file if it's been modified */
113 if (ISSET(MODIFIED))
114 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000115
Chris Allegretta355fbe52001-07-14 19:32:47 +0000116#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000117 /* then save all of the other modified loaded files, if any */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000118 if (open_files != NULL) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000119 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000120
121 tmp = open_files;
122
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000123 while (open_files->prev != NULL)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000124 open_files = open_files->prev;
125
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000126 while (open_files->next != NULL) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000127
128 /* if we already saved the file above (i. e. if it was the
129 currently loaded file), don't save it again */
130 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000131 /* make sure open_files->fileage and fileage, and
132 open_files->filebot and filebot, are in sync; they
133 might not be if lines have been cut from the top or
134 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000135 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000136 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000137 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000138 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000139 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000140 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000141 open_files = open_files->next;
142 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000143 }
144#endif
145
Chris Allegretta6df90f52002-07-19 01:08:59 +0000146 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000147}
148
Chris Allegretta6df90f52002-07-19 01:08:59 +0000149void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000150{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000151 char *ret;
Chris Allegretta48b06702002-02-22 04:30:50 +0000152 int i = -1;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000153
Chris Allegretta6df90f52002-07-19 01:08:59 +0000154 /* If we can't save, we have REAL bad problems, but we might as well
155 TRY. */
156 if (die_filename[0] == '\0')
157 ret = get_next_filename("nano.save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000158 else {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000159 char *buf = charalloc(strlen(die_filename) + 6);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000160
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000161 strcpy(buf, die_filename);
162 strcat(buf, ".save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000163 ret = get_next_filename(buf);
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000164 free(buf);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000165 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000166 if (ret[0] != '\0')
167 i = write_file(ret, 1, 0, 0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000168
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000169 if (i != -1)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000170 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000171 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000172 fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000173
174 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000175}
176
Chris Allegrettae61e8302001-01-14 05:18:27 +0000177/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000178 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000179void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000180{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000181 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000182}
183
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000184void print_view_warning(void)
185{
186 statusbar(_("Key illegal in VIEW mode"));
187}
188
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +0000189/* Initialize global variables -- no better way for now. If
Chris Allegretta6df90f52002-07-19 01:08:59 +0000190 * save_cutbuffer is nonzero, don't set cutbuffer to NULL. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000191void global_init(int save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000192{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000193 current_x = 0;
194 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000195
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000196 editwinrows = LINES - 5 + no_help();
197 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000198 die_too_small();
199
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000200 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000201 if (!save_cutbuffer)
202 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000203 current = NULL;
204 edittop = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000205 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000206 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000207 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000208
Chris Allegretta6fe61492001-05-21 12:56:25 +0000209#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000210 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000211 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000212 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000213 if (fill < 0)
214 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000215#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000216
Chris Allegretta88b09152001-05-17 11:35:43 +0000217 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000218 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000219 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000220}
221
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000222void window_init(void)
223{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000224 editwinrows = LINES - 5 + no_help();
225 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000226 die_too_small();
227
Chris Allegretta1a128af2003-01-26 04:15:56 +0000228 if (edit != NULL)
229 delwin(edit);
230 if (topwin != NULL)
231 delwin(topwin);
232 if (bottomwin != NULL)
233 delwin(bottomwin);
234
David Lawrence Ramsey27863662003-08-29 21:31:37 +0000235 /* Set up the main text window. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000236 edit = newwin(editwinrows, COLS, 2, 0);
237
David Lawrence Ramsey27863662003-08-29 21:31:37 +0000238 /* And the other windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000239 topwin = newwin(2, COLS, 0, 0);
240 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
241
David Lawrence Ramsey53809442004-01-30 04:29:52 +0000242 /* Turn the keypad on, so that it still works after a Meta-X. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000243 keypad(edit, TRUE);
244 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000245}
246
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000247#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000248void mouse_init(void)
249{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000250 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000251 mousemask(BUTTON1_RELEASED, NULL);
252 mouseinterval(50);
253 } else
254 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000255}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000256#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000257
258#ifndef DISABLE_HELP
259/* This function allocates help_text, and stores the help string in it.
260 * help_text should be NULL initially. */
261void help_init(void)
262{
Chris Allegretta908f7702003-01-15 11:18:58 +0000263 size_t allocsize = 1; /* space needed for help_text */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000264 char *ptr = NULL;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000265 const shortcut *s;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000266#ifndef NANO_SMALL
267 const toggle *t;
268#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000269
270 /* First set up the initial help text for the current function */
271 if (currshortcut == whereis_list || currshortcut == replace_list
272 || currshortcut == replace_list_2)
273 ptr = _("Search Command Help Text\n\n "
274 "Enter the words or characters you would like to search "
275 "for, then hit enter. If there is a match for the text you "
276 "entered, the screen will be updated to the location of the "
277 "nearest match for the search string.\n\n "
Chris Allegretta37d594c2003-01-05 22:00:41 +0000278 "The previous search string will be shown in brackets after "
279 "the Search: prompt. Hitting Enter without entering any text "
280 "will perform the previous search.\n\n The following function "
281 "keys are available in Search mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000282 else if (currshortcut == goto_list)
283 ptr = _("Go To Line Help Text\n\n "
284 "Enter the line number that you wish to go to and hit "
285 "Enter. If there are fewer lines of text than the "
286 "number you entered, you will be brought to the last line "
287 "of the file.\n\n The following function keys are "
288 "available in Go To Line mode:\n\n");
289 else if (currshortcut == insertfile_list)
290 ptr = _("Insert File Help Text\n\n "
291 "Type in the name of a file to be inserted into the current "
292 "file buffer at the current cursor location.\n\n "
293 "If you have compiled nano with multiple file buffer "
294 "support, and enable multiple buffers with the -F "
295 "or --multibuffer command line flags, the Meta-F toggle, or "
296 "a nanorc file, inserting a file will cause it to be "
297 "loaded into a separate buffer (use Meta-< and > to switch "
298 "between file buffers).\n\n If you need another blank "
299 "buffer, do not enter any filename, or type in a "
300 "nonexistent filename at the prompt and press "
301 "Enter.\n\n The following function keys are "
302 "available in Insert File mode:\n\n");
303 else if (currshortcut == writefile_list)
304 ptr = _("Write File Help Text\n\n "
305 "Type the name that you wish to save the current file "
306 "as and hit Enter to save the file.\n\n If you have "
307 "selected text with Ctrl-^, you will be prompted to "
308 "save only the selected portion to a separate file. To "
309 "reduce the chance of overwriting the current file with "
310 "just a portion of it, the current filename is not the "
311 "default in this mode.\n\n The following function keys "
312 "are available in Write File mode:\n\n");
313#ifndef DISABLE_BROWSER
314 else if (currshortcut == browser_list)
315 ptr = _("File Browser Help Text\n\n "
316 "The file browser is used to visually browse the "
317 "directory structure to select a file for reading "
318 "or writing. You may use the arrow keys or Page Up/"
319 "Down to browse through the files, and S or Enter to "
320 "choose the selected file or enter the selected "
321 "directory. To move up one level, select the directory "
322 "called \"..\" at the top of the file list.\n\n The "
323 "following function keys are available in the file "
324 "browser:\n\n");
325 else if (currshortcut == gotodir_list)
326 ptr = _("Browser Go To Directory Help Text\n\n "
327 "Enter the name of the directory you would like to "
328 "browse to.\n\n If tab completion has not been disabled, "
329 "you can use the TAB key to (attempt to) automatically "
330 "complete the directory name.\n\n The following function "
331 "keys are available in Browser Go To Directory mode:\n\n");
332#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000333#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000334 else if (currshortcut == spell_list)
335 ptr = _("Spell Check Help Text\n\n "
336 "The spell checker checks the spelling of all text "
337 "in the current file. When an unknown word is "
338 "encountered, it is highlighted and a replacement can "
339 "be edited. It will then prompt to replace every "
340 "instance of the given misspelled word in the "
341 "current file.\n\n The following other functions are "
342 "available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000343#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000344#ifndef NANO_SMALL
345 else if (currshortcut == extcmd_list)
346 ptr = _("External Command Help Text\n\n "
347 "This menu allows you to insert the output of a command "
348 "run by the shell into the current buffer (or a new "
349 "buffer in multibuffer mode).\n\n The following keys are "
350 "available in this mode:\n\n");
351#endif
352 else /* Default to the main help list */
353 ptr = _(" nano help text\n\n "
354 "The nano editor is designed to emulate the functionality and "
355 "ease-of-use of the UW Pico text editor. There are four main "
356 "sections of the editor: The top line shows the program "
357 "version, the current filename being edited, and whether "
358 "or not the file has been modified. Next is the main editor "
359 "window showing the file being edited. The status line is "
360 "the third line from the bottom and shows important messages. "
361 "The bottom two lines show the most commonly used shortcuts "
362 "in the editor.\n\n "
363 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000364 "sequences are notated with a caret (^) symbol and can be "
365 "entered either by using the Control (Ctrl) key or pressing the "
366 "Esc key twice. Escape-key sequences are notated with the Meta "
367 "(M) symbol and can be entered using either the Esc, Alt or "
368 "Meta key depending on your keyboard setup. Also, pressing Esc "
369 "twice and then typing a three-digit number from 000 to 255 "
370 "will enter the character with the corresponding ASCII code. "
371 "The following keystrokes are available in the main editor "
372 "window. Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000373
Chris Allegretta908f7702003-01-15 11:18:58 +0000374 allocsize += strlen(ptr);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000375
376 /* The space needed for the shortcut lists, at most COLS characters,
377 * plus '\n'. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000378 allocsize += (COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000379
380#ifndef NANO_SMALL
381 /* If we're on the main list, we also count the toggle help text.
382 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
383 * COLS - 24 characters, plus '\n'.*/
Chris Allegretta3a784062003-02-10 02:32:58 +0000384 if (currshortcut == main_list) {
385 size_t endislen = strlen(_("enable/disable"));
386
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000387 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000388 allocsize += 8 + strlen(t->desc) + endislen;
389 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000390#endif /* !NANO_SMALL */
391
392 /* help_text has been freed and set to NULL unless the user resized
393 * while in the help screen. */
394 free(help_text);
395
396 /* Allocate space for the help text */
Chris Allegretta908f7702003-01-15 11:18:58 +0000397 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000398
399 /* Now add the text we want */
400 strcpy(help_text, ptr);
401 ptr = help_text + strlen(help_text);
402
403 /* Now add our shortcut info */
404 for (s = currshortcut; s != NULL; s = s->next) {
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000405 /* true if the character in s->metaval is shown in first column */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000406 int meta_shortcut = 0;
407
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000408 if (s->ctrlval != NANO_NO_KEY) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000409#ifndef NANO_SMALL
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000410 if (s->ctrlval == NANO_HISTORY_KEY)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000411 ptr += sprintf(ptr, "%.2s", _("Up"));
412 else
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000413#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000414 if (s->ctrlval == NANO_CONTROL_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000415 ptr += sprintf(ptr, "^%.5s", _("Space"));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000416 else if (s->ctrlval == NANO_CONTROL_8)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000417 ptr += sprintf(ptr, "^?");
418 else
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000419 ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000420 }
421#ifndef NANO_SMALL
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000422 else if (s->metaval != NANO_NO_KEY) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000423 meta_shortcut = 1;
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000424 if (s->metaval == NANO_ALT_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000425 ptr += snprintf(ptr, 8, "M-%.5s", _("Space"));
426 else
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000427 ptr += sprintf(ptr, "M-%c", toupper(s->metaval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000428 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000429#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000430
431 *(ptr++) = '\t';
432
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000433 if (s->funcval != NANO_NO_KEY)
434 ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000435
436 *(ptr++) = '\t';
437
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000438 if (!meta_shortcut && s->metaval != NANO_NO_KEY)
439 ptr += sprintf(ptr, "(M-%c)", toupper(s->metaval));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000440 else if (meta_shortcut && s->miscval != NANO_NO_KEY)
441 ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000442
443 *(ptr++) = '\t';
444
445 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000446 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000447 }
448
449#ifndef NANO_SMALL
450 /* And the toggles... */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000451 if (currshortcut == main_list) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000452 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000453 assert(t->desc != NULL);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000454 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val), t->desc,
Chris Allegretta3a784062003-02-10 02:32:58 +0000455 _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000456 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000457 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000458#endif /* !NANO_SMALL */
459
460 /* If all went well, we didn't overwrite the allocated space for
461 help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000462 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000463}
464#endif
465
466/* Create a new filestruct node. Note that we specifically do not set
467 * prevnode->next equal to the new line. */
468filestruct *make_new_node(filestruct *prevnode)
469{
470 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
471
472 newnode->data = NULL;
473 newnode->prev = prevnode;
474 newnode->next = NULL;
475 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
476
477 return newnode;
478}
479
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000480/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000481filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000482{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000483 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000484
Chris Allegretta6df90f52002-07-19 01:08:59 +0000485 assert(src != NULL);
486
Chris Allegretta88b09152001-05-17 11:35:43 +0000487 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000488 dst->next = src->next;
489 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000490 strcpy(dst->data, src->data);
491 dst->lineno = src->lineno;
492
493 return dst;
494}
495
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000496/* Splice a node into an existing filestruct. */
497void splice_node(filestruct *begin, filestruct *newnode, filestruct *end)
498{
499 if (newnode != NULL) {
500 newnode->next = end;
501 newnode->prev = begin;
502 }
503 if (begin != NULL)
504 begin->next = newnode;
505 if (end != NULL)
506 end->prev = newnode;
507}
508
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000509/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000510void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000511{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000512 assert(fileptr != NULL);
513
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000514 if (fileptr->prev != NULL)
515 fileptr->prev->next = fileptr->next;
516
517 if (fileptr->next != NULL)
518 fileptr->next->prev = fileptr->prev;
519}
520
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000521/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000522void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000523{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000524 if (fileptr != NULL) {
525 if (fileptr->data != NULL)
526 free(fileptr->data);
527 free(fileptr);
528 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000529}
530
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000531/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000532filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000533{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000534 filestruct *head; /* copy of src, top of the copied list */
535 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000536
Chris Allegretta6df90f52002-07-19 01:08:59 +0000537 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000538
Chris Allegretta6df90f52002-07-19 01:08:59 +0000539 prev = copy_node(src);
540 prev->prev = NULL;
541 head = prev;
542 src = src->next;
543 while (src != NULL) {
544 prev->next = copy_node(src);
545 prev->next->prev = prev;
546 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000547
Chris Allegretta6df90f52002-07-19 01:08:59 +0000548 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000549 }
550
Chris Allegretta6df90f52002-07-19 01:08:59 +0000551 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000552 return head;
553}
554
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000555/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000556void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000557{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000558 if (src != NULL) {
559 while (src->next != NULL) {
560 src = src->next;
561 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000562#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000563 fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_node()");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000564#endif
565 }
566 delete_node(src);
567#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000568 fprintf(stderr, "%s: free'd last node.\n", "delete_node()");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000569#endif
570 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000571}
572
Chris Allegretta6df90f52002-07-19 01:08:59 +0000573void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000574{
575 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000576 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000577
Chris Allegretta6df90f52002-07-19 01:08:59 +0000578 assert(fileage == NULL || fileage != fileage->next);
579 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000580 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000581}
582
Chris Allegretta6df90f52002-07-19 01:08:59 +0000583void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000584{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000585 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000586 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000587 else {
588 int lineno = fileptr->prev->lineno;
589
590 assert(fileptr != fileptr->next);
591 for (; fileptr != NULL; fileptr = fileptr->next)
592 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000593 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000594}
595
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000596/* Print one usage string to the screen, removes lots of duplicate
Chris Allegretta6df90f52002-07-19 01:08:59 +0000597 * strings to translate and takes out the parts that shouldn't be
598 * translatable (the flag names). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000599void print1opt(const char *shortflag, const char *longflag,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000600 const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000601{
602 printf(" %s\t", shortflag);
603 if (strlen(shortflag) < 8)
604 printf("\t");
605
606#ifdef HAVE_GETOPT_LONG
607 printf("%s\t", longflag);
608 if (strlen(longflag) < 8)
609 printf("\t\t");
610 else if (strlen(longflag) < 16)
611 printf("\t");
612#endif
613
614 printf("%s\n", desc);
615}
616
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000617void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000618{
619#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000620 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
621 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000622#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000623 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
624 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000625#endif /* HAVE_GETOPT_LONG */
626
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000627 print1opt("-h, -?", "--help", _("Show this message"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000628 print1opt(_("+LINE"), "", _("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000629#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000630 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000631 print1opt("-D", "--dos", _("Write file in DOS format"));
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +0000632 print1opt("-E", "--backupdir=[dir]", _("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000633#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000634#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000635 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000636#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000637#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000638#ifndef NANO_SMALL
Chris Allegretta36fec722003-01-22 01:13:25 +0000639 print1opt("-H", "--historylog", _("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000640#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000641 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
642#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000643#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000644 print1opt("-M", "--mac", _("Write file in Mac format"));
645 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000646#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000647#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000648 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000649#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000650#ifdef HAVE_REGEX_H
651 print1opt("-R", "--regexp", _("Do regular expression searches"));
652#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000653#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000654 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000655#endif
David Lawrence Ramseya7c93642004-02-25 03:19:29 +0000656 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), _("Set width of a tab in cols to #cols"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000657 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000658#ifdef ENABLE_COLOR
659 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
660#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000661 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000662#ifndef NANO_SMALL
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000663 print1opt("-d", "--rebinddelete", _("Fix Backspace/Delete confusion problem"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000664 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
665 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000666#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000667 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000668#ifndef DISABLE_MOUSE
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000669 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000670#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000671#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000672 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000673#endif
Jordi Mallacheeb50042003-01-18 22:42:34 +0000674 print1opt("-p", "--preserve", _("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000675#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000676 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000677#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000678#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000679 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000680#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000681 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
682 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000683#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000684 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000685#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000686 print1opt("-x", "--nohelp", _("Don't show help window"));
687 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000688
689 /* this is a special case */
690 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000691
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000692 exit(0);
693}
694
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000695void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000696{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000697 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000698 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000699 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000700 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000701 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000702
Chris Allegrettae6600372003-01-17 03:39:41 +0000703#ifndef ENABLE_NLS
704 printf(" --disable-nls");
705#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000706#ifdef DEBUG
707 printf(" --enable-debug");
708#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000709#ifdef NANO_EXTRA
710 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000711#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000712#ifdef NANO_SMALL
713 printf(" --enable-tiny");
714#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000715#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000716 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000717#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000718#ifdef DISABLE_HELP
719 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000720#endif
721#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000722 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000723#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000724#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +0000725 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000726#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000727#ifdef DISABLE_OPERATINGDIR
728 printf(" --disable-operatingdir");
729#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000730#ifdef DISABLE_SPELLER
731 printf(" --disable-speller");
732#endif
733#ifdef DISABLE_TABCOMP
734 printf(" --disable-tabcomp");
735#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000736#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000737#ifdef DISABLE_WRAPPING
738 printf(" --disable-wrapping");
739#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000740#ifdef DISABLE_ROOTWRAP
741 printf(" --disable-wrapping-as-root");
742#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000743#ifdef ENABLE_COLOR
744 printf(" --enable-color");
745#endif
746#ifdef ENABLE_MULTIBUFFER
747 printf(" --enable-multibuffer");
748#endif
749#ifdef ENABLE_NANORC
750 printf(" --enable-nanorc");
751#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000752#ifdef USE_SLANG
753 printf(" --with-slang");
754#endif
755 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000756}
757
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000758/* Stuff we do when we abort from programs and want to clean up the
759 * screen. This doesn't do much right now. */
760void do_early_abort(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000761{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000762 blank_statusbar_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000763}
764
765int no_help(void)
766{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000767 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000768}
769
Chris Allegrettad865da12002-07-29 23:46:38 +0000770#if defined(DISABLE_JUSTIFY) || defined(DISABLE_SPELLER) || defined(DISABLE_HELP) || defined(NANO_SMALL)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000771void nano_disabled_msg(void)
772{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000773 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000774}
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000775#endif
Chris Allegrettaff269f82000-12-01 18:46:01 +0000776
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000777#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000778static int pid; /* This is the PID of the newly forked process
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000779 * below. It must be global since the signal
780 * handler needs it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000781RETSIGTYPE cancel_fork(int signal)
782{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000783 if (kill(pid, SIGKILL) == -1)
784 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000785}
786
787int open_pipe(const char *command)
788{
789 int fd[2];
790 FILE *f;
791 struct sigaction oldaction, newaction;
792 /* original and temporary handlers for SIGINT */
793#ifdef _POSIX_VDISABLE
794 struct termios term, newterm;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000795#endif /* _POSIX_VDISABLE */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000796 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000797 /* cancel_sigs == 1 means that sigaction() failed without changing
798 * the signal handlers. cancel_sigs == 2 means the signal handler
799 * was changed, but the tcsetattr didn't succeed.
800 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000801 * I use this variable since it is important to put things back when
802 * we finish, even if we get errors. */
803
804 /* Make our pipes. */
805
806 if (pipe(fd) == -1) {
807 statusbar(_("Could not pipe"));
808 return 1;
809 }
810
811 /* Fork a child. */
812
813 if ((pid = fork()) == 0) {
814 close(fd[0]);
815 dup2(fd[1], fileno(stdout));
816 dup2(fd[1], fileno(stderr));
817 /* If execl() returns at all, there was an error. */
818
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000819 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000820 exit(0);
821 }
822
823 /* Else continue as parent. */
824
825 close(fd[1]);
826
827 if (pid == -1) {
828 close(fd[0]);
829 statusbar(_("Could not fork"));
830 return 1;
831 }
832
833 /* Before we start reading the forked command's output, we set
834 * things up so that ^C will cancel the new process. */
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000835 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000836 cancel_sigs = 1;
837 nperror("sigaction");
838 } else {
839 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000840 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000841 cancel_sigs = 1;
842 nperror("sigaction");
843 }
844 }
845 /* Note that now oldaction is the previous SIGINT signal handler,
846 * to be restored later. */
847
848 /* See if the platform supports disabling individual control
849 * characters. */
850#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000851 if (cancel_sigs == 0 && tcgetattr(0, &term) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000852 cancel_sigs = 2;
853 nperror("tcgetattr");
854 }
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000855 if (cancel_sigs == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000856 newterm = term;
857 /* Grab oldterm's VINTR key :-) */
858 newterm.c_cc[VINTR] = oldterm.c_cc[VINTR];
859 if (tcsetattr(0, TCSANOW, &newterm) == -1) {
860 cancel_sigs = 2;
861 nperror("tcsetattr");
862 }
863 }
864#endif /* _POSIX_VDISABLE */
865
866 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000867 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000868 nperror("fdopen");
869
870 read_file(f, "stdin", 0);
871 /* if multibuffer mode is on, we could be here in view mode; if so,
872 don't set the modification flag */
873 if (!ISSET(VIEW_MODE))
874 set_modified();
875
876 if (wait(NULL) == -1)
877 nperror("wait");
878
879#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000880 if (cancel_sigs == 0 && tcsetattr(0, TCSANOW, &term) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000881 nperror("tcsetattr");
882#endif /* _POSIX_VDISABLE */
883
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000884 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000885 nperror("sigaction");
886
887 return 0;
888}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +0000889#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000890
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000891#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000892void do_mouse(void)
893{
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000894 int mouse_x, mouse_y;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000895
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000896 if (get_mouseinput(&mouse_x, &mouse_y, 1) == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000897
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000898 /* Click in the edit window to move the cursor, but only when
899 we're not in a subfunction. */
900 if (wenclose(edit, mouse_y, mouse_x) && currshortcut == main_list) {
901 int sameline;
902 /* Did they click on the line with the cursor? If they
903 clicked on the cursor, we set the mark. */
904 size_t xcur;
905 /* The character they clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000906
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000907 /* Subtract out size of topwin. Perhaps we need a constant
908 somewhere? */
909 mouse_y -= 2;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000910
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000911 sameline = (mouse_y == current_y);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000912
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000913 /* Move to where the click occurred. */
914 for (; current_y < mouse_y && current->next != NULL; current_y++)
915 current = current->next;
916 for (; current_y > mouse_y && current->prev != NULL; current_y--)
917 current = current->prev;
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000918
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000919 xcur = actual_x(current->data, get_page_start(xplustabs()) +
920 mouse_x);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000921
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000922 /* Selecting where the cursor is toggles the mark. As does
923 selecting beyond the line length with the cursor at the
924 end of the line. */
925 if (sameline && xcur == current_x) {
926 if (ISSET(VIEW_MODE)) {
927 print_view_warning();
928 return;
929 }
930 do_mark();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000931 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000932
933 current_x = xcur;
934 placewewant = xplustabs();
935 edit_refresh();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000936 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000937 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000938 /* FIXME: If we clicked on a location in the statusbar, the cursor
939 should move to the location we clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000940}
941#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000942
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000943/* The user typed a character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000944void do_char(char ch)
945{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000946 size_t current_len = strlen(current->data);
947#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
948 int refresh = 0;
949 /* Do we have to run edit_refresh(), or can we get away with
950 * update_line()? */
951#endif
952
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000953 if (ch == '\0') /* Null to newline, if needed. */
954 ch = '\n';
955 else if (ch == '\n') { /* Newline to Enter, if needed. */
956 do_enter();
957 return;
958 }
959
960 assert(current != NULL && current->data != NULL);
961
962 /* When a character is inserted on the current magicline, it means
963 * we need a new one! */
David Lawrence Ramseyb9775152004-03-19 02:15:42 +0000964 if (filebot == current)
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000965 new_magicline();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000966
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000967 /* More dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000968 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000969 assert(current_x <= current_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000970 charmove(&current->data[current_x + 1], &current->data[current_x],
971 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000972 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000973 totsize++;
974 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000975
Chris Allegretta6df90f52002-07-19 01:08:59 +0000976#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000977 /* Note that current_x has not yet been incremented. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000978 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000979 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +0000980#endif
981
Chris Allegretta6df90f52002-07-19 01:08:59 +0000982 do_right();
983
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000984#ifndef DISABLE_WRAPPING
Chris Allegrettadffa2072002-07-24 01:02:26 +0000985 if (!ISSET(NO_WRAP) && ch != '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +0000986 refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000987#endif
988
Chris Allegretta6df90f52002-07-19 01:08:59 +0000989#ifdef ENABLE_COLOR
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +0000990 if (ISSET(COLOR_SYNTAX))
991 refresh = 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000992#endif
993
994#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
995 if (refresh)
996 edit_refresh();
997#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000998}
999
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001000int do_verbatim_input(void)
1001{
David Lawrence Ramseyee383db2004-02-06 03:07:10 +00001002 int *verbatim_kbinput; /* Used to hold verbatim input. */
1003 int verbatim_len; /* Length of verbatim input. */
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001004 int i;
1005
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001006 statusbar(_("Verbatim input"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001007 verbatim_kbinput = get_verbatim_kbinput(edit, &verbatim_len, 1);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001008
1009 /* Turn on DISABLE_CURPOS while inserting character(s) and turn it
1010 * off afterwards, so that if constant cursor position display is
1011 * on, it will be updated properly. */
1012 SET(DISABLE_CURPOS);
1013 for (i = 0; i < verbatim_len; i++)
David Lawrence Ramsey815cba82004-02-07 03:07:01 +00001014 do_char((char)verbatim_kbinput[i]);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001015 UNSET(DISABLE_CURPOS);
1016
1017 free(verbatim_kbinput);
1018
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001019 return 1;
1020}
1021
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001022int do_backspace(void)
1023{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001024 if (current != fileage || current_x > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001025 do_left();
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001026 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001027 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001028 return 1;
1029}
1030
1031int do_delete(void)
1032{
1033 int refresh = 0;
1034
1035 /* blbf -> blank line before filebot (see below) */
1036 int blbf = 0;
1037
1038 if (current->next == filebot && current->data[0] == '\0')
1039 blbf = 1;
1040
1041 placewewant = xplustabs();
1042
1043 if (current_x != strlen(current->data)) {
1044 /* Let's get dangerous */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001045 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001046 strlen(current->data) - current_x);
1047
1048 align(&current->data);
1049#ifdef ENABLE_COLOR
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +00001050 if (ISSET(COLOR_SYNTAX))
1051 refresh = 1;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001052#endif
1053 } else if (current->next != NULL && (current->next != filebot || blbf)) {
1054 /* We can delete the line before filebot only if it is blank: it
1055 becomes the new magic line then. */
1056
1057 filestruct *foo;
1058
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001059 current->data = charealloc(current->data,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001060 strlen(current->data) +
1061 strlen(current->next->data) + 1);
1062 strcat(current->data, current->next->data);
1063
1064 foo = current->next;
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001065 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001066 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001067
1068 unlink_node(foo);
1069 delete_node(foo);
1070 renumber(current);
1071 totlines--;
1072 refresh = 1;
1073 } else
1074 return 0;
1075
1076 totsize--;
1077 set_modified();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001078 update_line(current, current_x);
1079 if (refresh)
1080 edit_refresh();
1081 return 1;
1082}
1083
1084int do_tab(void)
1085{
1086 do_char('\t');
1087 return 1;
1088}
1089
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001090/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001091int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001092{
Chris Allegrettae3167732001-03-18 16:59:34 +00001093 filestruct *newnode;
Chris Allegretta68532c32001-09-17 13:49:33 +00001094 char *tmp;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001095
Chris Allegretta6df90f52002-07-19 01:08:59 +00001096 newnode = make_new_node(current);
1097 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001098 tmp = &current->data[current_x];
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001099
Chris Allegrettaff989832001-09-17 13:48:00 +00001100#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001101 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001102 if (ISSET(AUTOINDENT)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001103 int extra = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001104 const char *spc = current->data;
1105
1106 while (*spc == ' ' || *spc == '\t') {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001107 extra++;
1108 spc++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001109 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001110 /* If current_x < extra, then we are breaking the line in the
1111 * indentation. Autoindenting should add only current_x
1112 * characters of indentation. */
Chris Allegrettadab017e2002-04-23 10:56:06 +00001113 if (current_x < extra)
1114 extra = current_x;
1115 else
1116 current_x = extra;
1117 totsize += extra;
1118
1119 newnode->data = charalloc(strlen(tmp) + extra + 1);
1120 strncpy(newnode->data, current->data, extra);
1121 strcpy(&newnode->data[extra], tmp);
Chris Allegrettaff989832001-09-17 13:48:00 +00001122 } else
1123#endif
1124 {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001125 current_x = 0;
Chris Allegretta88b09152001-05-17 11:35:43 +00001126 newnode->data = charalloc(strlen(tmp) + 1);
Chris Allegrettae3167732001-03-18 16:59:34 +00001127 strcpy(newnode->data, tmp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001128 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001129 *tmp = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001130
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001131 if (current->next == NULL)
Chris Allegrettae3167732001-03-18 16:59:34 +00001132 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001133 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001134
1135 totsize++;
1136 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001137 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001138 align(&current->data);
1139
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001140 /* The logic here is as follows:
1141 * -> If we are at the bottom of the buffer, we want to recenter
Chris Allegretta88520c92001-05-05 17:45:54 +00001142 * (read: rebuild) the screen and forcibly move the cursor.
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001143 * -> otherwise, we want simply to redraw the screen and update
1144 * where we think the cursor is.
1145 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001146 if (current_y == editwinrows - 1) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001147#ifndef NANO_SMALL
1148 if (ISSET(SMOOTHSCROLL))
1149 edit_update(current, NONE);
1150 else
1151#endif
1152 edit_update(current, CENTER);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001153 reset_cursor();
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001154 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001155 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001156 edit_refresh();
1157 update_cursor();
1158 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001159
1160 totlines++;
1161 set_modified();
1162
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001163 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001164 return 1;
1165}
1166
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001167#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001168int do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001169{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001170 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001171
Chris Allegretta6df90f52002-07-19 01:08:59 +00001172 /* Skip letters in this word first. */
1173 while (current->data[current_x] != '\0' &&
1174 isalnum((int)current->data[current_x]))
1175 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001176
Chris Allegretta6df90f52002-07-19 01:08:59 +00001177 for (; current != NULL; current = current->next) {
1178 while (current->data[current_x] != '\0' &&
1179 !isalnum((int)current->data[current_x]))
1180 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001181
Chris Allegretta6df90f52002-07-19 01:08:59 +00001182 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001183 break;
1184
Chris Allegretta6df90f52002-07-19 01:08:59 +00001185 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001186 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001187 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001188 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001189
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001190 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001191
David Lawrence Ramseybf3c93e2004-03-13 19:42:58 +00001192 /* Refresh the screen. If current has run off the bottom, this
1193 * call puts it at the center line. */
1194 edit_refresh();
1195
Chris Allegretta6232d662002-05-12 19:52:15 +00001196 return 0;
1197}
1198
Chris Allegretta6df90f52002-07-19 01:08:59 +00001199/* The same thing for backwards. */
1200int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001201{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001202 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001203
Chris Allegretta6df90f52002-07-19 01:08:59 +00001204 /* Skip letters in this word first. */
1205 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1206 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001207
Chris Allegretta6df90f52002-07-19 01:08:59 +00001208 for (; current != NULL; current = current->prev) {
1209 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1210 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001211
Chris Allegretta6df90f52002-07-19 01:08:59 +00001212 if (current_x >= 0)
1213 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001214
Chris Allegretta6df90f52002-07-19 01:08:59 +00001215 if (current->prev != NULL)
1216 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001217 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001218
Chris Allegretta6df90f52002-07-19 01:08:59 +00001219 if (current != NULL) {
1220 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1221 current_x--;
1222 } else {
1223 current = fileage;
1224 current_x = 0;
1225 }
1226
Chris Allegretta76e291b2001-10-14 19:05:10 +00001227 placewewant = xplustabs();
1228
David Lawrence Ramseyb6aa4282004-03-14 01:42:17 +00001229 /* Refresh the screen. If current has run off the top, this call
1230 * puts it at the center line. */
1231 edit_refresh();
1232
Chris Allegretta6232d662002-05-12 19:52:15 +00001233 return 0;
1234}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001235#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001236
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001237int do_mark(void)
1238{
1239#ifdef NANO_SMALL
1240 nano_disabled_msg();
1241#else
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001242 TOGGLE(MARK_ISSET);
1243 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001244 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001245 mark_beginbuf = current;
1246 mark_beginx = current_x;
1247 } else {
1248 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001249 edit_refresh();
1250 }
1251#endif
1252 return 1;
1253}
1254
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001255#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001256void wrap_reset(void)
1257{
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001258 same_line_wrap = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001259}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001260#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001261
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001262#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001263/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001264 * moved forward since the last typed character. Return value:
1265 * whether we wrapped. */
1266int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001267{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001268 size_t len = strlen(inptr->data); /* length of the line we wrap */
1269 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001270 int wrap_loc = -1; /* index of inptr->data where we wrap */
1271 int word_back = -1;
1272#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001273 const char *indentation = NULL;
1274 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001275 int indent_len = 0; /* strlen(indentation) */
1276#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001277 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001278 int after_break_len; /* strlen(after_break) */
1279 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001280 const char *wrap_line = NULL;
1281 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001282 int wrap_line_len = 0; /* strlen(wrap_line) */
1283 char *newline = NULL; /* the line we create */
1284 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001285
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001286/* There are three steps. First, we decide where to wrap. Then, we
1287 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001288
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001289/* Step 1, finding where to wrap. We are going to add a new-line
1290 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001291 * location of this replacement.
1292 *
1293 * Where should we break the line? We need the last "legal wrap point"
1294 * such that the last word before it ended at or before fill. If there
1295 * is no such point, we settle for the first legal wrap point.
1296 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001297 * A "legal wrap point" is a white-space character that is not followed by
1298 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001299 *
1300 * If there is no legal wrap point or we found the last character of the
1301 * line, we should return without wrapping.
1302 *
1303 * Note that the initial indentation does not count as a legal wrap
1304 * point if we are going to auto-indent!
1305 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001306 * Note that the code below could be optimised, by not calling strnlenpt()
1307 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001308
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001309#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001310 if (ISSET(AUTOINDENT))
1311 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001312#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001313 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001314 for (; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001315 /* record where the last word ended */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001316 if (*wrap_line != ' ' && *wrap_line != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001317 word_back = i;
1318 /* if we have found a "legal wrap point" and the current word
1319 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001320 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001321 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001322 /* we record the latest "legal wrap point" */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001323 if (word_back != i && wrap_line[1] != ' ' && wrap_line[1] != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001324 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001325 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001326 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001327 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001328
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001329/* Step 2, making the new wrap line. It will consist of indentation +
1330 * after_break + " " + wrap_line (although indentation and wrap_line are
1331 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001332
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001333 /* after_break is the text that will be moved to the next line. */
1334 after_break = inptr->data + wrap_loc + 1;
1335 after_break_len = len - wrap_loc - 1;
1336 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001337
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001338 /* new_line_len will later be increased by the lengths of indentation
1339 * and wrap_line. */
1340 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001341
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001342 /* We prepend the wrapped text to the next line, if the flag is set,
1343 * and there is a next line, and prepending would not make the line
1344 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001345 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001346 wrap_line = inptr->next->data;
1347 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001348
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001349 /* +1 for the space between after_break and wrap_line */
1350 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1351 wrapping = 1;
1352 new_line_len += (1 + wrap_line_len);
1353 }
1354 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001355
Chris Allegrettaff989832001-09-17 13:48:00 +00001356#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001357 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001358 /* Indentation comes from the next line if wrapping, else from
1359 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001360 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001361 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001362 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001363 /* The wrap_line text should not duplicate indentation.
1364 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001365 wrap_line += indent_len;
1366 else
1367 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001368 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001369#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001370
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001371 /* Now we allocate the new line and copy into it. */
1372 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1373 *newline = '\0';
1374
1375#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001376 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001377 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001378 newline[indent_len] = '\0';
1379 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001380#endif
1381 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001382 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001383 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001384 null_at(&inptr->data, wrap_loc + 1);
1385 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001386 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001387 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001388 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001389 * in a tab or a space, we don't add a space and decrement
1390 * totsize to account for that. */
Chris Allegrettad127c712003-02-12 23:20:45 +00001391 if (!isspace((int) newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001392 strcat(newline, " ");
1393 else
1394 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001395 strcat(newline, wrap_line);
1396 free(inptr->next->data);
1397 inptr->next->data = newline;
1398 } else {
1399 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001400
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001401 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001402 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001403#ifndef NANO_SMALL
1404 totsize += indent_len;
1405#endif
1406 totlines++;
1407 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001408 temp->prev = inptr;
1409 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001410 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001411 /* If temp->next is NULL, then temp is the last line of the
1412 * file, so we must set filebot. */
1413 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001414 temp->next->prev = temp;
1415 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001416 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001417 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001418
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001419/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1420 * other sundry things. */
1421
1422 /* later wraps of this line will be prepended to the next line. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001423 same_line_wrap = 1;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001424
1425 /* Each line knows its line number. We recalculate these if we
1426 * inserted a new line. */
1427 if (!wrapping)
1428 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001429
Chris Allegretta6df90f52002-07-19 01:08:59 +00001430 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001431 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001432 current = current->next;
1433 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001434#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001435 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001436#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001437 wrap_loc + 1;
1438 wrap_reset();
1439 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001440 }
1441
Chris Allegretta6df90f52002-07-19 01:08:59 +00001442#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001443 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001444 * If it was on the next line and we wrapped, we must move it
1445 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001446 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1447 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001448 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001449 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001450 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001451#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001452
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001453 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001454 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001455
1456 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001457}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001458#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001459
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001460#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001461/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001462 * return zero if the user cancels. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001463int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001464{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001465 char *save_search;
1466 char *save_replace;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001467 filestruct *current_save = current;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001468 size_t current_x_save = current_x;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001469 filestruct *edittop_save = edittop;
1470 /* Save where we are. */
1471 int i = 0;
1472 /* The return value. */
1473 int reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001474#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001475 int case_sens_set = ISSET(CASE_SENSITIVE);
1476 int mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001477
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001478 SET(CASE_SENSITIVE);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001479 /* Make sure the marking highlight is off during spell-check. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001480 UNSET(MARK_ISSET);
1481#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001482 /* Make sure spell-check goes forward only. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001483 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001484
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001485 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001486 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001487 save_search = last_search;
1488 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001489
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001490 /* Set search/replace strings to misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001491 last_search = mallocstrcpy(NULL, word);
1492 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001493
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001494 /* Start from the top of the file. */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001495 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001496 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001497
1498 search_last_line = FALSE;
1499
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001500 /* Find the first whole-word occurrence of word. */
1501 while (findnextstr(TRUE, TRUE, fileage, 0, word, FALSE) != 0)
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001502 if (is_whole_word(current_x, current->data, word)) {
1503 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001504
Chris Allegretta6df90f52002-07-19 01:08:59 +00001505 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001506
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001507 /* Allow the replace word to be corrected. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001508 i = statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001509#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001510 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001511#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001512 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001513
Chris Allegretta6df90f52002-07-19 01:08:59 +00001514 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001515
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001516 if (i != -1 && strcmp(word, answer)) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001517 search_last_line = FALSE;
1518 current_x--;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001519 do_replace_loop(word, current_save, &current_x_save, TRUE);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001520 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001521
1522 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001523 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001524
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001525 /* Restore the search/replace strings. */
1526 free(last_search);
1527 last_search = save_search;
1528 free(last_replace);
1529 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001530
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001531 /* Restore where we were. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001532 current = current_save;
1533 current_x = current_x_save;
1534 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001535
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001536 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001537 if (reverse_search_set)
1538 SET(REVERSE_SEARCH);
1539
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001540#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001541 if (!case_sens_set)
1542 UNSET(CASE_SENSITIVE);
1543
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001544 /* Restore marking highlight. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001545 if (mark_set)
1546 SET(MARK_ISSET);
1547#endif
1548
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001549 return i != -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001550}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001551
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001552/* Integrated spell checking using 'spell' program. Return value: NULL
1553 * for normal termination, otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001554char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001555{
Chris Allegretta271e9722000-11-10 18:15:43 +00001556 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001557 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001558 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001559 pid_t pid_spell, pid_sort, pid_uniq;
1560 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001561
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001562 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001563 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1564 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001565
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001566 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001567
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001568 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001569 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001570
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001571 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001572
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001573 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001574
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001575 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001576 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1577 goto close_pipes_and_exit;
1578
1579 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1580 goto close_pipes_and_exit;
1581
Chris Allegretta271e9722000-11-10 18:15:43 +00001582 close(tempfile_fd);
1583
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001584 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001585 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1586 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001587
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001588 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001589
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001590 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001591 execlp("spell", "spell", NULL);
1592
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001593 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001594 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001595 }
1596
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001597 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001598 close(spell_fd[1]);
1599
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001600 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001601 if ((pid_sort = fork()) == 0) {
1602
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001603 /* Child continues (i.e, future spell process). Replace the
1604 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001605 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1606 goto close_pipes_and_exit;
1607
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001608 close(spell_fd[0]);
1609
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001610 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001611 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1612 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001613
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001614 close(sort_fd[1]);
1615
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001616 /* Start sort program. Use -f to remove mixed case without
1617 * having to have ANOTHER pipe for tr. If this isn't portable,
1618 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001619 execlp("sort", "sort", "-f", NULL);
1620
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001621 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001622 exit(1);
1623 }
1624
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001625 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001626 close(sort_fd[1]);
1627
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001628 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001629 if ((pid_uniq = fork()) == 0) {
1630
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001631 /* Child continues (i.e, future uniq process). Replace the
1632 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001633 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1634 goto close_pipes_and_exit;
1635
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001636 close(sort_fd[0]);
1637
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001638 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001639 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1640 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001641
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001642 close(uniq_fd[1]);
1643
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001644 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001645 execlp("uniq", "uniq", NULL);
1646
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001647 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001648 exit(1);
1649 }
1650
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001651 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001652 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001653
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001654 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001655 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1656 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001657 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001658 }
1659
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001660 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001661 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1662 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001663 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001664 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001665
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001666 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001667 read_buff_read = 0;
1668 read_buff_size = pipe_buff_size + 1;
1669 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001670
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001671 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001672 read_buff_read += bytesread;
1673 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001674 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001675 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001676
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001677 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001678
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001679 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001680 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001681
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001682 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001683 read_buff_word = read_buff_ptr = read_buff;
1684
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001685 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001686
1687 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001688 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001689 if (read_buff_word != read_buff_ptr) {
1690 if (!do_int_spell_fix(read_buff_word)) {
1691 read_buff_word = read_buff_ptr;
1692 break;
1693 }
1694 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001695 read_buff_word = read_buff_ptr + 1;
1696 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001697 read_buff_ptr++;
1698 }
1699
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001700 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001701 if (read_buff_word != read_buff_ptr)
1702 do_int_spell_fix(read_buff_word);
1703
Chris Allegretta271e9722000-11-10 18:15:43 +00001704 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001705 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001706 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001707
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001708 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001709 waitpid(pid_spell, &spell_status, 0);
1710 waitpid(pid_sort, &sort_status, 0);
1711 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001712
Chris Allegretta334a9402002-12-16 04:25:53 +00001713 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1714 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001715
Chris Allegretta334a9402002-12-16 04:25:53 +00001716 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1717 return _("Error invoking \"sort -f\"");
1718
1719 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1720 return _("Error invoking \"uniq\"");
1721
1722 /* Otherwise... */
1723 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001724
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001725 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001726
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001727 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001728 close(tempfile_fd);
1729 close(spell_fd[0]);
1730 close(spell_fd[1]);
1731 close(sort_fd[0]);
1732 close(sort_fd[1]);
1733 close(uniq_fd[0]);
1734 close(uniq_fd[1]);
1735 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001736}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001737
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001738/* External spell checking. Return value: NULL for normal termination,
1739 * otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001740char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001741{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001742 int alt_spell_status, lineno_cur = current->lineno;
1743 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001744 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001745 char *ptr;
1746 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001747 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001748#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001749 int mark_set = ISSET(MARK_ISSET);
1750 int mbb_lineno_cur = 0;
1751 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001752 * the alternate spell command. The line that mark_beginbuf
1753 * points to will be freed, so we save the line number and
1754 * restore afterwards. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001755
1756 if (mark_set) {
1757 mbb_lineno_cur = mark_beginbuf->lineno;
1758 UNSET(MARK_ISSET);
1759 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001760#endif
1761
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001762 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001763
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001764 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001765 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001766 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001767
Chris Allegrettae434b452001-01-27 19:25:00 +00001768 spellargs[0] = strtok(alt_speller, " ");
1769 while ((ptr = strtok(NULL, " ")) != NULL) {
1770 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001771 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001772 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001773 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001774 spellargs[arglen - 1] = NULL;
1775 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001776 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001777
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001778 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001779 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001780 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00001781 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001782
1783 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001784 exit(1);
1785 }
1786
1787 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001788 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001789 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001790
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001791 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001792 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001793
Chris Allegretta334a9402002-12-16 04:25:53 +00001794 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1795 char *altspell_error = NULL;
1796 char *invoke_error = _("Could not invoke \"%s\"");
1797 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1798
1799 altspell_error = charalloc(msglen);
1800 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1801 return altspell_error;
1802 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001803
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001804 refresh();
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001805#ifndef NANO_SMALL
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001806 if (!mark_set) {
1807 /* Only reload the temp file if it isn't a marked selection. */
1808#endif
1809 free_filestruct(fileage);
1810 global_init(1);
1811 open_file(tempfile_name, 0, 1);
1812#ifndef NANO_SMALL
1813 }
1814
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001815 if (mark_set) {
1816 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1817 mark_beginbuf = current;
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001818 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001819 mark_beginx = current_x;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001820 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001821 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001822#endif
1823
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001824 /* Go back to the old position, mark the file as modified, and make
1825 * sure that the titlebar is refreshed. */
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001826 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001827 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001828 clearok(topwin, FALSE);
1829 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001830
Chris Allegretta334a9402002-12-16 04:25:53 +00001831 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001832}
1833#endif
1834
1835int do_spell(void)
1836{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001837#ifdef DISABLE_SPELLER
Chris Allegrettaff269f82000-12-01 18:46:01 +00001838 nano_disabled_msg();
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001839 return 1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001840#else
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001841 int i;
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001842 char *temp, *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001843
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001844 if ((temp = safe_tempnam(0, "nano.")) == NULL) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001845 statusbar(_("Could not create a temporary filename: %s"),
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001846 strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001847 return 0;
1848 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001849
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001850#ifndef NANO_SMALL
1851 if (ISSET(MARK_ISSET))
1852 i = write_marked(temp, 1, 0, 0);
1853 else
1854#endif
1855 i = write_file(temp, 1, 0, 0);
1856
1857 if (i == -1) {
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001858 statusbar(_("Spell checking failed: unable to write temp file!"));
Chris Allegrettabef12972002-03-06 03:30:40 +00001859 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001860 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001861 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001862
Chris Allegrettae1f14522001-09-19 03:19:43 +00001863#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001864 /* Update the current open_files entry before spell-checking, in
1865 * case any problems occur. */
Chris Allegretta48b06702002-02-22 04:30:50 +00001866 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001867#endif
1868
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001869 if (alt_speller != NULL)
Chris Allegretta334a9402002-12-16 04:25:53 +00001870 spell_msg = do_alt_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001871 else
Chris Allegretta334a9402002-12-16 04:25:53 +00001872 spell_msg = do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001873 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001874 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001875
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001876 if (spell_msg != NULL) {
Chris Allegretta334a9402002-12-16 04:25:53 +00001877 statusbar(_("Spell checking failed: %s"), spell_msg);
1878 return 0;
1879 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001880
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001881 statusbar(_("Finished checking spelling"));
1882 return 1;
Chris Allegrettadbc12b22000-07-03 03:10:14 +00001883#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00001884}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001885
Chris Allegrettad865da12002-07-29 23:46:38 +00001886#if !defined(DISABLE_WRAPPING) && !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001887/* The "indentation" of a line is the white-space between the quote part
1888 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001889size_t indent_length(const char *line)
1890{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001891 size_t len = 0;
1892
1893 assert(line != NULL);
1894 while (*line == ' ' || *line == '\t') {
1895 line++;
1896 len++;
1897 }
1898 return len;
1899}
Chris Allegrettadffa2072002-07-24 01:02:26 +00001900#endif /* !DISABLE_WRAPPING && !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001901
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001902#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00001903/* justify_format() replaces Tab by Space and multiple spaces by 1 (except
1904 * it maintains 2 after a . ! or ?). Note the terminating \0
1905 * counts as a space.
1906 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001907 * If !changes_allowed and justify_format() needs to make a change, it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001908 * returns 1, otherwise returns 0.
1909 *
1910 * If changes_allowed, justify_format() might make line->data
1911 * shorter, and change the actual pointer with null_at().
1912 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001913 * justify_format() will not look at the first skip characters of line.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001914 * skip should be at most strlen(line->data). The skip+1st character must
1915 * not be whitespace. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001916int justify_format(int changes_allowed, filestruct *line, size_t skip)
1917{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001918 const char *punct = ".?!";
1919 const char *brackets = "'\")}]>";
Chris Allegretta6df90f52002-07-19 01:08:59 +00001920 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001921
Chris Allegretta6df90f52002-07-19 01:08:59 +00001922 /* These four asserts are assumptions about the input data. */
1923 assert(line != NULL);
1924 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001925 assert(skip < strlen(line->data));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001926 assert(line->data[skip] != ' ' && line->data[skip] != '\t');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001927
Chris Allegretta6df90f52002-07-19 01:08:59 +00001928 back = line->data + skip;
1929 front = back;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001930 for (front = back; ; front++) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001931 int remove_space = 0;
1932 /* Do we want to remove this space? */
1933
Chris Allegretta6df90f52002-07-19 01:08:59 +00001934 if (*front == '\t') {
1935 if (!changes_allowed)
1936 return 1;
1937 *front = ' ';
1938 }
1939 /* these tests are safe since line->data + skip is not a space */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001940 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001941 const char *bob = front - 2;
1942
1943 remove_space = 1;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001944 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001945 if (strchr(punct, *bob) != NULL) {
1946 remove_space = 0;
1947 break;
1948 }
1949 if (strchr(brackets, *bob) == NULL)
1950 break;
1951 }
1952 }
1953
1954 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001955 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001956 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001957 if (!changes_allowed)
1958 return 1;
1959#ifndef NANO_SMALL
1960 if (mark_beginbuf == line && back - line->data < mark_beginx)
1961 mark_beginx--;
1962#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001963 if (*front == '\0')
1964 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00001965 } else {
1966 *back = *front;
1967 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001968 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001969 if (*front == '\0')
1970 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001971 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001972
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001973 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00001974 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00001975
1976 /* This assert merely documents a fact about the loop above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001977 assert(changes_allowed != 0 || back == front);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001978
1979 /* Now back is the new end of line->data. */
1980 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00001981 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001982 null_at(&line->data, back - line->data);
1983#ifndef NANO_SMALL
1984 if (mark_beginbuf == line && back - line->data < mark_beginx)
1985 mark_beginx = back - line->data;
1986#endif
1987 }
1988 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001989}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001990
1991/* The "quote part" of a line is the largest initial substring matching
1992 * the quote string. This function returns the length of the quote part
1993 * of the given line.
1994 *
1995 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1996 * quotestr. */
1997#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001998size_t quote_length(const char *line, const regex_t *qreg)
1999{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002000 regmatch_t matches;
2001 int rc = regexec(qreg, line, 1, &matches, 0);
2002
2003 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
2004 return 0;
2005 /* matches.rm_so should be 0, since the quote string should start with
2006 * the caret ^. */
2007 return matches.rm_eo;
2008}
2009#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002010size_t quote_length(const char *line)
2011{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002012 size_t qdepth = 0;
2013 size_t qlen = strlen(quotestr);
2014
2015 /* Compute quote depth level */
2016 while (!strcmp(line + qdepth, quotestr))
2017 qdepth += qlen;
2018 return qdepth;
2019}
2020#endif /* !HAVE_REGEX_H */
2021
Chris Allegretta6df90f52002-07-19 01:08:59 +00002022/* a_line and b_line are lines of text. The quotation part of a_line is
2023 * the first a_quote characters. Check that the quotation part of
2024 * b_line is the same. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002025int quotes_match(const char *a_line, size_t a_quote,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002026 IFREG(const char *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002027{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002028 /* Here is the assumption about a_quote: */
2029 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00002030 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00002031 !strncmp(a_line, b_line, a_quote);
2032}
2033
2034/* We assume a_line and b_line have no quote part. Then, we return whether
2035 * b_line could follow a_line in a paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002036size_t indents_match(const char *a_line, size_t a_indent,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002037 const char *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002038{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002039 assert(a_indent == indent_length(a_line));
2040 assert(b_indent == indent_length(b_line));
2041
2042 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2043}
2044
2045/* Put the next par_len lines, starting with first_line, in the cut
2046 * buffer. We assume there are enough lines after first_line. We leave
2047 * copies of the lines in place, too. We return the new copy of
2048 * first_line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002049filestruct *backup_lines(filestruct *first_line, size_t par_len,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002050 size_t quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002051{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002052 /* We put the original lines, not copies, into the cut buffer, just
2053 * out of a misguided sense of consistency, so if you un-cut, you
2054 * get the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002055 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002056
2057 set_modified();
2058 cutbuffer = NULL;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002059 for (; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002060 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002061
Chris Allegretta908f7702003-01-15 11:18:58 +00002062 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002063 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002064 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002065 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002066 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002067 edittop = bob;
2068#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002069 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002070 mark_beginbuf = bob;
2071#endif
2072 justify_format(1, bob,
2073 quote_len + indent_length(bob->data + quote_len));
2074
Chris Allegretta908f7702003-01-15 11:18:58 +00002075 assert(alice != NULL && bob != NULL);
2076 add_to_cutbuffer(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002077 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002078 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002079 }
2080 return first_line;
2081}
2082
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002083/* Is it possible to break line at or before goal? */
2084int breakable(const char *line, int goal)
2085{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002086 for (; *line != '\0' && goal >= 0; line++) {
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002087 if (*line == ' ' || *line == '\t')
2088 return TRUE;
2089
2090 if (is_cntrl_char(*line) != 0)
2091 goal -= 2;
2092 else
2093 goal -= 1;
2094 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002095 /* If goal is not negative, the whole line (one word) was short
2096 * enough. */
2097 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002098}
2099
Chris Allegretta6df90f52002-07-19 01:08:59 +00002100/* We are trying to break a chunk off line. We find the last space such
2101 * that the display length to there is at most goal + 1. If there is
2102 * no such space, and force is not 0, then we find the first space.
2103 * Anyway, we then take the last space in that group of spaces. The
2104 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002105int break_line(const char *line, int goal, int force)
2106{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002107 /* Note that we use int instead of size_t, since goal is at most COLS,
2108 * the screen width, which will always be reasonably small. */
2109 int space_loc = -1;
2110 /* Current tentative return value. Index of the last space we
2111 * found with short enough display width. */
2112 int cur_loc = 0;
2113 /* Current index in line */
2114
2115 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002116 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002117 if (*line == ' ')
2118 space_loc = cur_loc;
2119 assert(*line != '\t');
2120
Chris Allegrettacf287c82002-07-20 13:57:41 +00002121 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002122 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002123 else
2124 goal--;
2125 }
2126 if (goal >= 0)
2127 /* In fact, the whole line displays shorter than goal. */
2128 return cur_loc;
2129 if (space_loc == -1) {
2130 /* No space found short enough. */
2131 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002132 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002133 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002134 return cur_loc;
2135 return -1;
2136 }
2137 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002138 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002139 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2140 *(line - cur_loc + space_loc + 1) == '\0')
2141 space_loc++;
2142 return space_loc;
2143}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002144
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002145/* Search a paragraph. If search_type is 0, search for the beginning of
2146 * the current paragraph or, if we're at the end of it, the beginning of
2147 * the next paragraph. If search_type is 1, search for the beginning of
2148 * the current paragraph or, if we're already there, the beginning of
2149 * the previous paragraph. If search_type is 2, search for the end of
2150 * the current paragraph or, if we're already there, the end of the next
2151 * paragraph. Afterwards, save the quote length, paragraph length, and
2152 * indentation length in *quote, *par, and *indent if they aren't NULL,
2153 * and refresh the screen if do_refresh is nonzero. Return 0 if we
2154 * found a paragraph, or 1 if there was an error or we didn't find a
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002155 * paragraph.
2156 *
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002157 * To explain the searching algorithm, I first need to define some
Chris Allegretta6df90f52002-07-19 01:08:59 +00002158 * phrases about paragraphs and quotation:
2159 * A line of text consists of a "quote part", followed by an
2160 * "indentation part", followed by text. The functions quote_length()
2161 * and indent_length() calculate these parts.
2162 *
2163 * A line is "part of a paragraph" if it has a part not in the quote
2164 * part or the indentation.
2165 *
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002166 * A line is "the beginning of a paragraph" if it is part of a
2167 * paragraph and
Chris Allegretta6df90f52002-07-19 01:08:59 +00002168 * 1) it is the top line of the file, or
2169 * 2) the line above it is not part of a paragraph, or
2170 * 3) the line above it does not have precisely the same quote
2171 * part, or
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002172 * 4) the indentation of this line is not an initial substring of
2173 * the indentation of the previous line, or
Chris Allegretta6df90f52002-07-19 01:08:59 +00002174 * 5) this line has no quote part and some indentation, and
2175 * AUTOINDENT is not set.
2176 * The reason for number 5) is that if AUTOINDENT is not set, then an
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002177 * indented line is expected to start a paragraph, like in books.
2178 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2179 * turned on.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002180 *
2181 * A contiguous set of lines is a "paragraph" if each line is part of
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002182 * a paragraph and only the first line is the beginning of a
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002183 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002184int do_para_search(int search_type, size_t *quote, size_t *par, size_t
2185 *indent, int do_refresh)
2186{
2187 size_t quote_len;
2188 /* Length of the initial quotation of the paragraph we
2189 * search. */
2190 size_t par_len;
2191 /* Number of lines in that paragraph. */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002192
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002193 /* We save this global variable to see if we're where we started
2194 * when searching for the beginning of the paragraph. */
2195 filestruct *current_save = current;
2196
2197 size_t indent_len; /* Generic indentation length. */
2198 filestruct *line; /* Generic line of text. */
2199
2200 static int do_restart = 1;
2201 /* Whether we're restarting when searching for the beginning
2202 * line of the paragraph. */
2203
2204#ifdef HAVE_REGEX_H
2205 regex_t qreg; /* qreg is the compiled quotation regexp. We no
2206 * longer care about quotestr. */
2207 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2208
2209 if (rc != 0) {
2210 size_t size = regerror(rc, &qreg, NULL, 0);
2211 char *strerror = charalloc(size);
2212
2213 regerror(rc, &qreg, strerror, size);
2214 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2215 free(strerror);
2216 return 1;
2217 }
2218#endif
2219
2220 /* Here is an assumption that is always true anyway. */
2221 assert(current != NULL);
2222
2223 current_x = 0;
2224
2225 restart_para_search:
2226/* Here we find the first line of the paragraph to search. If the
2227 * current line is in a paragraph, then we move back to the first line.
2228 * Otherwise we move to the first line that is in a paragraph. */
2229 quote_len = quote_length(IFREG(current->data, &qreg));
2230 indent_len = indent_length(current->data + quote_len);
2231
2232 if (current->data[quote_len + indent_len] != '\0') {
2233 /* This line is part of a paragraph. So we must search back to
2234 * the first line of this paragraph. First we check items 1)
2235 * and 3) above. */
2236 while (current->prev != NULL && quotes_match(current->data,
2237 quote_len, IFREG(current->prev->data, &qreg))) {
2238 size_t temp_id_len =
2239 indent_length(current->prev->data + quote_len);
2240 /* The indentation length of the previous line. */
2241
2242 /* Is this line the beginning of a paragraph, according to
2243 * items 2), 5), or 4) above? If so, stop. */
2244 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
2245 (quote_len == 0 && indent_len > 0
2246#ifndef NANO_SMALL
2247 && !ISSET(AUTOINDENT)
2248#endif
2249 ) ||
2250 !indents_match(current->prev->data + quote_len,
2251 temp_id_len, current->data + quote_len, indent_len))
2252 break;
2253 indent_len = temp_id_len;
2254 current = current->prev;
2255 current_y--;
2256 }
2257 } else if (search_type == 1) {
2258 /* This line is not part of a paragraph. Move up until we get
2259 * to a non "blank" line, and then move down once. */
2260 do {
2261 /* There is no previous paragraph, so nothing to move to. */
2262 if (current->prev == NULL) {
2263 placewewant = 0;
2264 if (do_refresh) {
2265 if (current_y < 0)
2266 edit_update(current, CENTER);
2267 else
2268 edit_refresh();
2269 }
2270#ifdef HAVE_REGEX_H
2271 if (!do_restart)
2272 regfree(&qreg);
2273#endif
2274 return 1;
2275 }
2276 current = current->prev;
2277 current_y--;
2278 quote_len = quote_length(IFREG(current->data, &qreg));
2279 indent_len = indent_length(current->data + quote_len);
2280 } while (current->data[quote_len + indent_len] == '\0');
2281 current = current->next;
2282 } else {
2283 /* This line is not part of a paragraph. Move down until we get
2284 * to a non "blank" line. */
2285 do {
2286 /* There is no next paragraph, so nothing to move to. */
2287 if (current->next == NULL) {
2288 placewewant = 0;
2289 if (do_refresh)
2290 edit_refresh();
2291#ifdef HAVE_REGEX_H
2292 regfree(&qreg);
2293#endif
2294 return 1;
2295 }
2296 current = current->next;
2297 current_y++;
2298 quote_len = quote_length(IFREG(current->data, &qreg));
2299 indent_len = indent_length(current->data + quote_len);
2300 } while (current->data[quote_len + indent_len] == '\0');
2301 }
2302
2303/* Now current is the first line of the paragraph, and quote_len is the
2304 * quotation length of that line. */
2305
2306/* Next step, compute par_len, the number of lines in this paragraph. */
2307 line = current;
2308 par_len = 1;
2309 indent_len = indent_length(line->data + quote_len);
2310
2311 while (line->next != NULL && quotes_match(current->data, quote_len,
2312 IFREG(line->next->data, &qreg))) {
2313 size_t temp_id_len = indent_length(line->next->data + quote_len);
2314
2315 if (!indents_match(line->data + quote_len, indent_len,
2316 line->next->data + quote_len, temp_id_len) ||
2317 line->next->data[quote_len + temp_id_len] == '\0' ||
2318 (quote_len == 0 && temp_id_len > 0
2319#ifndef NANO_SMALL
2320 && !ISSET(AUTOINDENT)
2321#endif
2322 ))
2323 break;
2324 indent_len = temp_id_len;
2325 line = line->next;
2326 par_len++;
2327 }
2328
2329 if (search_type == 1) {
2330 /* We're on the same line we started on. Move up until we get
2331 * to a non-"blank" line, restart the search from there until we
2332 * find a line that's part of a paragraph, and search once more
2333 * so that we end up at the beginning of that paragraph. */
2334 if (current != fileage && current == current_save && do_restart) {
2335 while (current->prev != NULL) {
2336 size_t i, j = 0;
2337 current = current->prev;
2338 current_y--;
2339 /* Skip over lines consisting only of spacing
2340 * characters, as searching for the end of the paragraph
2341 * does. */
2342 for (i = 0; current->data[i] != '\0'; i++) {
2343 if (isspace(current->data[i]))
2344 j++;
2345 else {
2346 i = 0;
2347 j = 1;
2348 break;
2349 }
2350 }
2351 if (i != j && strlen(current->data) >=
2352 (quote_len + indent_len) &&
2353 current->data[quote_len + indent_len] != '\0') {
2354 do_restart = 0;
2355 break;
2356 }
2357 }
2358 goto restart_para_search;
2359 } else
2360 do_restart = 1;
2361 }
2362
2363#ifdef HAVE_REGEX_H
2364 /* We no longer need to check quotation. */
2365 regfree(&qreg);
2366#endif
2367
2368/* Now par_len is the number of lines in this paragraph. We should
2369 * never call quotes_match() or quote_length() again. */
2370
2371 /* If we're searching for the end of the paragraph, move down the
2372 * number of lines in the paragraph. */
2373 if (search_type == 2) {
2374 for (; par_len > 0; current_y++, par_len--)
2375 current = current->next;
2376 }
2377
2378 /* Refresh the screen if needed. */
2379 if (do_refresh) {
2380 if (((search_type == 0 || search_type == 2) && current_y >
2381 editwinrows - 1) || (search_type == 1 && current_y < 0))
2382 edit_update(current, CENTER);
2383 else
2384 edit_refresh();
2385 }
2386
2387 /* Save the values of quote_len, par_len, and indent_len if
2388 * needed. */
2389 if (quote != NULL)
2390 *quote = quote_len;
2391 if (par != NULL)
2392 *par = par_len;
2393 if (indent != NULL)
2394 *indent = indent_len;
2395
2396 return 0;
2397}
2398
2399int do_para_begin(void)
2400{
2401 return do_para_search(1, NULL, NULL, NULL, TRUE);
2402}
2403
2404int do_para_end(void)
2405{
2406 return do_para_search(2, NULL, NULL, NULL, TRUE);
2407}
2408#endif
2409
2410/* Justify a paragraph. */
2411int do_justify(void)
2412{
2413#ifdef DISABLE_JUSTIFY
2414 nano_disabled_msg();
2415 return 1;
2416#else
Chris Allegretta6df90f52002-07-19 01:08:59 +00002417 size_t quote_len;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002418 /* Length of the initial quotation of the paragraph we
2419 * justify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002420 size_t par_len;
2421 /* Number of lines in that paragraph. */
2422 filestruct *first_mod_line = NULL;
2423 /* Will be the first line of the resulting justified paragraph
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002424 * that differs from the original. For restoring after
2425 * uncut. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002426 filestruct *last_par_line = current;
2427 /* Will be the last line of the result, also for uncut. */
2428 filestruct *cutbuffer_save = cutbuffer;
2429 /* When the paragraph gets modified, all lines from the changed
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002430 * one down are stored in the cut buffer. We back up the
2431 * original to restore it later. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002432
2433 /* We save these global variables to be restored if the user
2434 * unjustifies. Note we don't need to save totlines. */
2435 int current_x_save = current_x;
2436 int current_y_save = current_y;
2437 filestruct *current_save = current;
2438 int flags_save = flags;
2439 long totsize_save = totsize;
2440 filestruct *edittop_save = edittop;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002441#ifndef NANO_SMALL
2442 filestruct *mark_beginbuf_save = mark_beginbuf;
2443 int mark_beginx_save = mark_beginx;
2444#endif
2445
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002446 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002447 size_t i; /* Generic loop variable. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002448
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002449 /* First, search for the beginning of the current paragraph or, if
2450 * we're at the end of it, the beginning of the next paragraph.
2451 * Save the quote length, paragraph length, and indentation length
2452 * and don't refresh the screen yet (since we'll do that after we
2453 * justify). If the search failed, refresh the screen and get
2454 * out. */
2455 if (do_para_search(0, &quote_len, &par_len, &indent_len, FALSE) != 0) {
2456 edit_refresh();
2457 return 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002458 }
2459
Chris Allegretta6df90f52002-07-19 01:08:59 +00002460/* Next step, we loop through the lines of this paragraph, justifying
2461 * each one individually. */
Chris Allegretta8151ba52003-04-19 19:34:05 +00002462 SET(JUSTIFY_MODE);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002463 for (; par_len > 0; current_y++, par_len--) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002464 size_t line_len;
2465 size_t display_len;
2466 /* The width of current in screen columns. */
2467 int break_pos;
2468 /* Where we will break the line. */
2469
2470 indent_len = indent_length(current->data + quote_len) +
2471 quote_len;
2472 /* justify_format() removes excess spaces from the line, and
2473 * changes tabs to spaces. The first argument, 0, means don't
2474 * change the line, just say whether there are changes to be
2475 * made. If there are, we do backup_lines(), which copies the
2476 * original paragraph to the cutbuffer for unjustification, and
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002477 * then calls justify_format() on the remaining lines. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002478 if (first_mod_line == NULL && justify_format(0, current, indent_len))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002479 first_mod_line = backup_lines(current, par_len, quote_len);
2480
2481 line_len = strlen(current->data);
2482 display_len = strlenpt(current->data);
2483
2484 if (display_len > fill) {
2485 /* The line is too long. Try to wrap it to the next. */
2486 break_pos = break_line(current->data + indent_len,
2487 fill - strnlenpt(current->data, indent_len),
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002488 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002489 if (break_pos == -1 || break_pos + indent_len == line_len)
2490 /* We can't break the line, or don't need to, so just go
2491 * on to the next. */
2492 goto continue_loc;
2493 break_pos += indent_len;
2494 assert(break_pos < line_len);
2495 /* If we haven't backed up the paragraph, do it now. */
2496 if (first_mod_line == NULL)
2497 first_mod_line = backup_lines(current, par_len, quote_len);
2498 if (par_len == 1) {
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002499 /* There is no next line in this paragraph. We make a
2500 * new line and copy text after break_pos into it. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002501 splice_node(current, make_new_node(current),
2502 current->next);
Chris Allegretta428f6202003-02-12 03:21:45 +00002503 /* In a non-quoted paragraph, we copy the indent only if
2504 AUTOINDENT is turned on. */
2505 if (quote_len == 0)
2506#ifndef NANO_SMALL
2507 if (!ISSET(AUTOINDENT))
2508#endif
2509 indent_len = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002510 current->next->data = charalloc(indent_len + line_len -
2511 break_pos);
2512 strncpy(current->next->data, current->data,
2513 indent_len);
2514 strcpy(current->next->data + indent_len,
2515 current->data + break_pos + 1);
2516 assert(strlen(current->next->data) ==
2517 indent_len + line_len - break_pos - 1);
2518 totlines++;
2519 totsize += indent_len;
2520 par_len++;
2521 } else {
2522 size_t next_line_len = strlen(current->next->data);
2523
2524 indent_len = quote_len +
2525 indent_length(current->next->data + quote_len);
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002526 current->next->data = charealloc(current->next->data,
2527 next_line_len + line_len - break_pos + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002528
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00002529 charmove(current->next->data + indent_len + line_len - break_pos,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002530 current->next->data + indent_len,
2531 next_line_len - indent_len + 1);
2532 strcpy(current->next->data + indent_len,
2533 current->data + break_pos + 1);
2534 current->next->data[indent_len + line_len - break_pos - 1]
2535 = ' ';
2536#ifndef NANO_SMALL
2537 if (mark_beginbuf == current->next) {
2538 if (mark_beginx < indent_len)
2539 mark_beginx = indent_len;
2540 mark_beginx += line_len - break_pos;
2541 }
2542#endif
2543 }
2544#ifndef NANO_SMALL
2545 if (mark_beginbuf == current && mark_beginx > break_pos) {
2546 mark_beginbuf = current->next;
2547 mark_beginx -= break_pos + 1 - indent_len;
2548 }
2549#endif
2550 null_at(&current->data, break_pos);
2551 current = current->next;
2552 } else if (display_len < fill && par_len > 1) {
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002553 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002554
2555 indent_len = quote_len +
2556 indent_length(current->next->data + quote_len);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002557 /* If we can't pull a word from the next line up to this
2558 * one, just go on. */
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002559 if (!breakable(current->next->data + indent_len,
2560 fill - display_len - 1))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002561 goto continue_loc;
2562
2563 /* If we haven't backed up the paragraph, do it now. */
2564 if (first_mod_line == NULL)
2565 first_mod_line = backup_lines(current, par_len, quote_len);
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002566
2567 break_pos = break_line(current->next->data + indent_len,
2568 fill - display_len - 1, FALSE);
2569 assert(break_pos != -1);
2570
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002571 current->data = charealloc(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002572 line_len + break_pos + 2);
2573 current->data[line_len] = ' ';
2574 strncpy(current->data + line_len + 1,
2575 current->next->data + indent_len, break_pos);
2576 current->data[line_len + break_pos + 1] = '\0';
2577#ifndef NANO_SMALL
2578 if (mark_beginbuf == current->next) {
2579 if (mark_beginx < indent_len + break_pos) {
2580 mark_beginbuf = current;
2581 if (mark_beginx <= indent_len)
2582 mark_beginx = line_len + 1;
2583 else
2584 mark_beginx = line_len + 1 + mark_beginx - indent_len;
2585 } else
2586 mark_beginx -= break_pos + 1;
2587 }
2588#endif
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002589 next_line_len = strlen(current->next->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002590 if (indent_len + break_pos == next_line_len) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002591 filestruct *line = current->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002592
2593 /* Don't destroy edittop! */
2594 if (line == edittop)
2595 edittop = current;
2596
Chris Allegretta6df90f52002-07-19 01:08:59 +00002597 unlink_node(line);
2598 delete_node(line);
2599 totlines--;
2600 totsize -= indent_len;
2601 current_y--;
2602 } else {
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00002603 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002604 current->next->data + indent_len + break_pos + 1,
2605 next_line_len - break_pos - indent_len);
2606 null_at(&current->next->data,
2607 next_line_len - break_pos);
2608 current = current->next;
2609 }
2610 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002611 continue_loc:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002612 current = current->next;
2613 }
Chris Allegretta8151ba52003-04-19 19:34:05 +00002614 UNSET(JUSTIFY_MODE);
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002615
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002616/* We are now done justifying the paragraph. There are cleanup things
2617 * to do, and we check for unjustify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002618
2619 /* totlines, totsize, and current_y have been maintained above. We
2620 * now set last_par_line to the new end of the paragraph, update
2621 * fileage, set current_x. Also, edit_refresh() needs the line
2622 * numbers to be right, so we renumber(). */
2623 last_par_line = current->prev;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002624 if (first_mod_line != NULL) {
2625 if (first_mod_line->prev == NULL)
2626 fileage = first_mod_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002627 renumber(first_mod_line);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002628 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002629
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002630 if (current_y > editwinrows - 1)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002631 edit_update(current, CENTER);
2632 else
2633 edit_refresh();
2634
Chris Allegretta9149e612000-11-27 00:23:41 +00002635 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002636 /* Change the shortcut list to display the unjustify code. */
Chris Allegretta07798352000-11-27 22:58:23 +00002637 shortcut_init(1);
2638 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002639 reset_cursor();
2640
Chris Allegretta6df90f52002-07-19 01:08:59 +00002641 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002642 * keystroke and return. */
Chris Allegretta5f071802001-05-06 02:34:31 +00002643
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002644 {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002645 int meta_key;
2646 i = get_kbinput(edit, &meta_key);
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002647#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002648 /* If it was a mouse click, parse it with do_mouse() and it
2649 * might become the unjustify key. Else give it back to the
2650 * input stream. */
2651 if (i == KEY_MOUSE)
2652 do_mouse();
2653 else
2654 ungetch(i);
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002655 i = get_kbinput(edit, &meta_key);
Chris Allegretta5f071802001-05-06 02:34:31 +00002656#endif
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002657 }
Chris Allegretta5f071802001-05-06 02:34:31 +00002658
David Lawrence Ramseyc91696e2004-01-29 04:16:23 +00002659 if (i != NANO_UNJUSTIFY_KEY && i != NANO_UNJUSTIFY_FKEY) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002660 ungetch(i);
2661 /* Did we back up anything at all? */
2662 if (cutbuffer != cutbuffer_save)
2663 free_filestruct(cutbuffer);
2664 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002665 } else {
Chris Allegretta9149e612000-11-27 00:23:41 +00002666 /* Else restore the justify we just did (ungrateful user!) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002667 current = current_save;
2668 current_x = current_x_save;
2669 current_y = current_y_save;
2670 edittop = edittop_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002671 if (first_mod_line != NULL) {
2672 filestruct *cutbottom = get_cutbottom();
Chris Allegrettad022eac2000-11-27 02:50:49 +00002673
Chris Allegretta6df90f52002-07-19 01:08:59 +00002674 /* Splice the cutbuffer back into the file. */
2675 cutbottom->next = last_par_line->next;
2676 cutbottom->next->prev = cutbottom;
2677 /* The line numbers after the end of the paragraph have
2678 * been changed, so we change them back. */
2679 renumber(cutbottom->next);
2680 if (first_mod_line->prev != NULL) {
2681 cutbuffer->prev = first_mod_line->prev;
2682 cutbuffer->prev->next = cutbuffer;
2683 } else
2684 fileage = cutbuffer;
2685 cutbuffer = NULL;
2686
2687 last_par_line->next = NULL;
2688 free_filestruct(first_mod_line);
2689
2690 /* Restore global variables from before justify */
2691 totsize = totsize_save;
2692 totlines = filebot->lineno;
2693#ifndef NANO_SMALL
2694 mark_beginbuf = mark_beginbuf_save;
2695 mark_beginx = mark_beginx_save;
2696#endif
2697 flags = flags_save;
2698 if (!ISSET(MODIFIED)) {
2699 titlebar(NULL);
2700 wrefresh(topwin);
2701 }
2702 }
2703 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002704 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002705 cutbuffer = cutbuffer_save;
2706 blank_statusbar_refresh();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002707 /* display shortcut list with UnCut */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002708 shortcut_init(0);
2709 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002710
Chris Allegretta6df90f52002-07-19 01:08:59 +00002711 return 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002712#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002713}
2714
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002715int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002716{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002717 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002718
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002719 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002720
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002721#ifdef ENABLE_MULTIBUFFER
2722 if (!close_open_file()) {
2723 display_main_list();
2724 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002725 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002726 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002727#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002728 finish(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00002729 }
2730
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002731 if (ISSET(TEMP_OPT))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002732 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002733 else
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002734 i = do_yesno(FALSE, _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002735
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002736#ifdef DEBUG
2737 dump_buffer(fileage);
2738#endif
2739
2740 if (i == 1) {
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002741 if (do_writeout(TRUE) > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002742
2743#ifdef ENABLE_MULTIBUFFER
2744 if (!close_open_file()) {
2745 display_main_list();
2746 return 1;
2747 }
2748 else
2749#endif
2750 finish(0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002751 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002752 } else if (i == 0) {
2753
2754#ifdef ENABLE_MULTIBUFFER
2755 if (!close_open_file()) {
2756 display_main_list();
2757 return 1;
2758 }
2759 else
2760#endif
2761 finish(0);
2762 } else
2763 statusbar(_("Cancelled"));
2764
2765 display_main_list();
2766 return 1;
2767}
2768
2769void signal_init(void)
2770{
2771#ifdef _POSIX_VDISABLE
2772 struct termios term;
2773#endif
2774
2775 /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */
2776 memset(&act, 0, sizeof(struct sigaction));
2777 act.sa_handler = SIG_IGN;
2778 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00002779 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002780
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002781 /* Trap SIGHUP and SIGTERM cuz we want to write the file out. */
2782 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002783 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002784 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002785
2786#ifndef NANO_SMALL
2787 act.sa_handler = handle_sigwinch;
2788 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002789 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002790#endif
2791
2792#ifdef _POSIX_VDISABLE
2793 tcgetattr(0, &term);
2794
Chris Allegretta6cd143d2003-01-05 23:35:44 +00002795 if (!ISSET(PRESERVE)) {
2796 /* Ignore ^S and ^Q, much to Chris' chagrin */
2797 term.c_cc[VSTOP] = _POSIX_VDISABLE;
2798 term.c_cc[VSTART] = _POSIX_VDISABLE;
2799 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002800#ifdef VDSUSP
2801 term.c_cc[VDSUSP] = _POSIX_VDISABLE;
2802#endif /* VDSUSP */
2803
2804#endif /* _POSIX_VDISABLE */
2805
2806 if (!ISSET(SUSPEND)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002807 /* Insane! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002808#ifdef _POSIX_VDISABLE
2809 term.c_cc[VSUSP] = _POSIX_VDISABLE;
2810#else
2811 act.sa_handler = SIG_IGN;
2812 sigaction(SIGTSTP, &act, NULL);
2813#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002814 } else {
2815 /* If we don't do this, it seems other stuff interrupts the
2816 suspend handler! Try using nano with mutt without this
2817 line. */
2818 sigfillset(&act.sa_mask);
2819
2820 act.sa_handler = do_suspend;
2821 sigaction(SIGTSTP, &act, NULL);
2822
2823 act.sa_handler = do_cont;
2824 sigaction(SIGCONT, &act, NULL);
2825 }
2826
2827#ifdef _POSIX_VDISABLE
2828 tcsetattr(0, TCSANOW, &term);
2829#endif
2830}
2831
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002832/* Handler for SIGHUP and SIGTERM */
2833RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002834{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002835 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002836}
2837
2838/* What do we do when we catch the suspend signal */
2839RETSIGTYPE do_suspend(int signal)
2840{
2841 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002842 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002843 fflush(stdout);
2844
2845 /* Restore the terminal settings for the disabled keys */
2846 tcsetattr(0, TCSANOW, &oldterm);
2847
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002848 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
2849 suspended */
2850 act.sa_handler = handle_hupterm;
2851 sigaction(SIGHUP, &act, NULL);
2852 sigaction(SIGTERM, &act, NULL);
2853
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002854 /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002855 then we could be (and were) interrupted in the middle of the call.
2856 So we do it the mutt way instead */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002857 kill(0, SIGSTOP);
2858}
2859
2860/* Restore the suspend handler when we come back into the prog */
2861RETSIGTYPE do_cont(int signal)
2862{
2863 /* Now we just update the screen instead of having to reenable the
2864 SIGTSTP handler. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002865 doupdate();
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002866
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002867 /* The Hurd seems to need this, otherwise a ^Y after a ^Z will
David Lawrence Ramseya593f532003-11-28 19:47:42 +00002868 start suspending again. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002869 signal_init();
2870
2871#ifndef NANO_SMALL
2872 /* Perhaps the user resized the window while we slept. */
2873 handle_sigwinch(0);
2874#endif
2875}
2876
2877#ifndef NANO_SMALL
2878void handle_sigwinch(int s)
2879{
2880 const char *tty = ttyname(0);
2881 int fd;
2882 int result = 0;
2883 struct winsize win;
2884
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002885 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002886 return;
2887 fd = open(tty, O_RDWR);
2888 if (fd == -1)
2889 return;
2890 result = ioctl(fd, TIOCGWINSZ, &win);
2891 close(fd);
2892 if (result == -1)
2893 return;
2894
2895 /* Could check whether the COLS or LINES changed, and return
2896 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2897 * variables, and in some cases ncurses has already updated them.
2898 * But not in all cases, argh. */
2899 COLS = win.ws_col;
2900 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002901 editwinrows = LINES - 5 + no_help();
2902 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002903 die_too_small();
2904
2905#ifndef DISABLE_WRAPJUSTIFY
2906 fill = wrap_at;
2907 if (fill <= 0)
2908 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002909 if (fill < 0)
2910 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002911#endif
2912
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002913 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002914 memset(hblank, ' ', COLS);
2915 hblank[COLS] = '\0';
2916
2917#ifdef HAVE_RESIZETERM
2918 resizeterm(LINES, COLS);
2919#ifdef HAVE_WRESIZE
2920 if (wresize(topwin, 2, COLS) == ERR)
2921 die(_("Cannot resize top win"));
2922 if (mvwin(topwin, 0, 0) == ERR)
2923 die(_("Cannot move top win"));
2924 if (wresize(edit, editwinrows, COLS) == ERR)
2925 die(_("Cannot resize edit win"));
2926 if (mvwin(edit, 2, 0) == ERR)
2927 die(_("Cannot move edit win"));
2928 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
2929 die(_("Cannot resize bottom win"));
2930 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
2931 die(_("Cannot move bottom win"));
2932#endif /* HAVE_WRESIZE */
2933#endif /* HAVE_RESIZETERM */
2934
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002935 display_main_list();
2936 blank_statusbar();
2937 total_refresh();
2938
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002939 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002940 curs_set(1);
2941
David Lawrence Ramsey53809442004-01-30 04:29:52 +00002942 /* Turn the keypad on and switch to cbreak mode, so that the keypad
2943 * and input still work if we resized during verbatim input. */
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002944 keypad(edit, TRUE);
2945 keypad(bottomwin, TRUE);
David Lawrence Ramsey53809442004-01-30 04:29:52 +00002946#ifdef _POSIX_VDISABLE
2947 cbreak();
2948#endif
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002949
2950 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002951 siglongjmp(jmpbuf, 1);
2952}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002953
2954void allow_pending_sigwinch(int allow)
2955{
2956 sigset_t winch;
2957 sigemptyset(&winch);
2958 sigaddset(&winch, SIGWINCH);
2959 if (allow)
2960 sigprocmask(SIG_UNBLOCK, &winch, NULL);
2961 else
2962 sigprocmask(SIG_BLOCK, &winch, NULL);
2963}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002964#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002965
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002966/* If the NumLock key has made the keypad go awry, print an error
2967 message; hopefully we can address it later. */
2968void print_numlock_warning(void)
2969{
2970 static int didmsg = 0;
2971 if (!didmsg) {
2972 statusbar(_
2973 ("NumLock glitch detected. Keypad will malfunction with NumLock off"));
2974 didmsg = 1;
2975 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002976}
2977
Chris Allegrettadab017e2002-04-23 10:56:06 +00002978#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002979void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002980{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002981 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002982
Chris Allegretta658399a2001-06-14 02:54:22 +00002983 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002984 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002985
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002986 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002987 case TOGGLE_SUSPEND_KEY:
2988 signal_init();
2989 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002990#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00002991 case TOGGLE_MOUSE_KEY:
2992 mouse_init();
2993 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002994#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002995 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00002996 wclear(bottomwin);
2997 wrefresh(bottomwin);
2998 window_init();
2999 edit_refresh();
3000 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00003001 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00003002 case TOGGLE_DOS_KEY:
3003 UNSET(MAC_FILE);
3004 break;
3005 case TOGGLE_MAC_KEY:
3006 UNSET(DOS_FILE);
3007 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003008#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00003009 case TOGGLE_SYNTAX_KEY:
3010 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003011 break;
3012#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003013 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00003014
Chris Allegretta6df90f52002-07-19 01:08:59 +00003015 /* We are assuming here that shortcut_init() above didn't free and
3016 * reallocate the toggles. */
3017 enabled = ISSET(which->flag);
3018 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
3019 enabled = !enabled;
3020 statusbar("%s %s", which->desc,
3021 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00003022}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003023#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00003024
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003025int main(int argc, char *argv[])
3026{
3027 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003028 int startline = 0; /* Line to try and start at */
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003029 int modify_control_seq = 0;
Chris Allegretta09fc4302003-01-16 22:16:38 +00003030 int fill_flag_used = 0; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003031 const shortcut *s;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003032 int keyhandled = 0; /* Have we handled the keystroke yet? */
David Lawrence Ramseyf8ddf312004-01-09 22:38:09 +00003033 int kbinput; /* Input from keyboard */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003034 int meta_key;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003035
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003036#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003037 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003038#endif
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003039#ifdef _POSIX_VDISABLE
3040 struct termios term;
3041#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003042#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003043 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003044 {"help", 0, 0, 'h'},
3045#ifdef ENABLE_MULTIBUFFER
3046 {"multibuffer", 0, 0, 'F'},
3047#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003048#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003049#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003050 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003051#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003052 {"ignorercfiles", 0, 0, 'I'},
3053#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003054#ifndef DISABLE_JUSTIFY
3055 {"quotestr", 1, 0, 'Q'},
3056#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003057#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003058 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003059#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003060 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003061 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003062#ifdef ENABLE_COLOR
3063 {"syntax", 1, 0, 'Y'},
3064#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003065 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003066 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003067 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003068#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003069 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003070#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003071#ifndef DISABLE_OPERATINGDIR
3072 {"operatingdir", 1, 0, 'o'},
3073#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003074 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003075#ifndef DISABLE_WRAPJUSTIFY
3076 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003077#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003078#ifndef DISABLE_SPELLER
3079 {"speller", 1, 0, 's'},
3080#endif
3081 {"tempfile", 0, 0, 't'},
3082 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003083#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003084 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003085#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003086 {"nohelp", 0, 0, 'x'},
3087 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003088#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003089 {"backup", 0, 0, 'B'},
3090 {"dos", 0, 0, 'D'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003091 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003092 {"mac", 0, 0, 'M'},
3093 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003094 {"smooth", 0, 0, 'S'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003095 {"autoindent", 0, 0, 'i'},
3096 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003097#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003098 {0, 0, 0, 0}
3099 };
3100#endif
3101
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003102#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003103 setlocale(LC_ALL, "");
3104 bindtextdomain(PACKAGE, LOCALEDIR);
3105 textdomain(PACKAGE);
3106#endif
3107
Chris Allegretta7662c862003-01-13 01:35:15 +00003108#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003109 /* if we don't have rcfile support, we're root, and
3110 --disable-wrapping-as-root is used, turn wrapping off */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003111 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003112 SET(NO_WRAP);
3113#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003114
3115#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003116 while ((optchr = getopt_long(argc, argv, "h?BDE:FHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz",
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003117 long_options, NULL)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003118#else
3119 while ((optchr =
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003120 getopt(argc, argv, "h?BDE:FHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003121#endif
3122
3123 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003124
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003125 case 'a':
3126 case 'b':
3127 case 'e':
3128 case 'f':
3129 case 'g':
3130 case 'j':
3131 /* Pico compatibility flags */
3132 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003133#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003134 case 'B':
3135 SET(BACKUP_FILE);
3136 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003137 case 'D':
3138 SET(DOS_FILE);
3139 break;
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003140 case 'E':
3141 backup_dir = mallocstrcpy(backup_dir, optarg);
3142 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003143#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003144#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003145 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003146 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003147 break;
3148#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003149#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003150#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003151 case 'H':
3152 SET(HISTORYLOG);
3153 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003154#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003155 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003156 SET(NO_RCFILE);
3157 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003158#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003159#ifndef NANO_SMALL
3160 case 'M':
3161 SET(MAC_FILE);
3162 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003163 case 'N':
3164 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003165 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003166#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003167#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003168 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003169 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003170 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003171#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003172#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003173 case 'R':
3174 SET(USE_REGEXP);
3175 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003176#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003177#ifndef NANO_SMALL
3178 case 'S':
3179 SET(SMOOTHSCROLL);
3180 break;
3181#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003182 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003183 {
3184 int i;
3185 char *first_error;
3186
Chris Allegretta7662c862003-01-13 01:35:15 +00003187 /* Using strtol() instead of atoi() lets us accept 0
3188 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003189 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003190 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003191 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003192 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003193 tabsize = i;
3194 if (tabsize <= 0) {
3195 fprintf(stderr, _("Tab size is too small for nano...\n"));
3196 exit(1);
3197 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003198 }
3199 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003200 case 'V':
3201 version();
3202 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003203#ifdef ENABLE_COLOR
3204 case 'Y':
3205 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3206 break;
3207#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003208 case 'c':
3209 SET(CONSTUPDATE);
3210 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003211 case 'd':
3212 SET(REBIND_DELETE);
3213 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003214#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003215 case 'i':
3216 SET(AUTOINDENT);
3217 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003218 case 'k':
3219 SET(CUT_TO_END);
3220 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003221#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003222 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003223 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003224 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003225#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003226 case 'm':
3227 SET(USE_MOUSE);
3228 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003229#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003230#ifndef DISABLE_OPERATINGDIR
3231 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003232 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003233 break;
3234#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003235 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003236 SET(PRESERVE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003237 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003238#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003239 case 'r':
3240 {
3241 int i;
3242 char *first_error;
3243
Chris Allegretta7662c862003-01-13 01:35:15 +00003244 /* Using strtol() instead of atoi() lets us accept 0
3245 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003246 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003247 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003248 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003249 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003250 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003251 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003252 fill_flag_used = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003253 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003254#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003255#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003256 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003257 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003258 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003259#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003260 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003261 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003262 break;
3263 case 'v':
3264 SET(VIEW_MODE);
3265 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003266#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003267 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003268 SET(NO_WRAP);
3269 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003270#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003271 case 'x':
3272 SET(NO_HELP);
3273 break;
3274 case 'z':
3275 SET(SUSPEND);
3276 break;
3277 default:
3278 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003279 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003280 }
3281
Chris Allegretta7662c862003-01-13 01:35:15 +00003282/* We've read through the command line options. Now back up the flags
3283 and values that are set, and read the rcfile(s). If the values
3284 haven't changed afterward, restore the backed-up values. */
3285#ifdef ENABLE_NANORC
3286 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003287#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003288 char *operating_dir_cpy = operating_dir;
3289#endif
3290#ifndef DISABLE_WRAPPING
3291 int wrap_at_cpy = wrap_at;
3292#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003293#ifndef NANO_SMALL
3294 char *backup_dir_cpy = backup_dir;
3295#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003296#ifndef DISABLE_JUSTIFY
3297 char *quotestr_cpy = quotestr;
3298#endif
3299#ifndef DISABLE_SPELLER
3300 char *alt_speller_cpy = alt_speller;
3301#endif
3302 int tabsize_cpy = tabsize;
3303 long flags_cpy = flags;
3304
Chris Allegretta5ec68622003-02-05 02:39:34 +00003305#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003306 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003307#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003308#ifndef NANO_SMALL
3309 backup_dir = NULL;
3310#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003311#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003312 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003313#endif
3314#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003315 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003316#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003317
3318 do_rcfile();
3319
3320#ifndef DISABLE_OPERATINGDIR
3321 if (operating_dir_cpy != NULL) {
3322 free(operating_dir);
3323 operating_dir = operating_dir_cpy;
3324 }
3325#endif
3326#ifndef DISABLE_WRAPPING
3327 if (fill_flag_used)
3328 wrap_at = wrap_at_cpy;
3329#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003330#ifndef NANO_SMALL
3331 if (backup_dir_cpy != NULL) {
3332 free(backup_dir);
3333 backup_dir = backup_dir_cpy;
3334 }
3335#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003336#ifndef DISABLE_JUSTIFY
3337 if (quotestr_cpy != NULL) {
3338 free(quotestr);
3339 quotestr = quotestr_cpy;
3340 }
3341#endif
3342#ifndef DISABLE_SPELLER
3343 if (alt_speller_cpy != NULL) {
3344 free(alt_speller);
3345 alt_speller = alt_speller_cpy;
3346 }
3347#endif
3348 if (tabsize_cpy > 0)
3349 tabsize = tabsize_cpy;
3350 flags |= flags_cpy;
3351 }
3352#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003353 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003354 SET(NO_WRAP);
3355#endif
3356#endif /* ENABLE_NANORC */
3357
Chris Allegrettad8451932003-03-11 03:50:40 +00003358#ifndef NANO_SMALL
3359 history_init();
3360#ifdef ENABLE_NANORC
3361 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3362 load_history();
3363#endif
3364#endif
3365
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003366#ifndef NANO_SMALL
3367 /* Set up the backup directory. This entails making sure it exists
3368 * and is a directory, so that backup files will be saved there. */
3369 init_backup_dir();
3370#endif
3371
Chris Allegretta7662c862003-01-13 01:35:15 +00003372#ifndef DISABLE_OPERATINGDIR
3373 /* Set up the operating directory. This entails chdir()ing there,
3374 so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003375 init_operating_dir();
3376#endif
3377
Chris Allegretta7662c862003-01-13 01:35:15 +00003378#ifndef DISABLE_JUSTIFY
3379 if (quotestr == NULL)
3380#ifdef HAVE_REGEX_H
3381 quotestr = mallocstrcpy(NULL, "^([ \t]*[|>:}#])+");
3382#else
3383 quotestr = mallocstrcpy(NULL, "> ");
3384#endif
3385#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003386
Chris Allegretta7662c862003-01-13 01:35:15 +00003387 if (tabsize == -1)
3388 tabsize = 8;
3389
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003390 /* Clear the filename we'll be using */
3391 filename = charalloc(1);
3392 filename[0] = '\0';
3393
Chris Allegretta7662c862003-01-13 01:35:15 +00003394 /* If there's a +LINE flag, it is the first non-option argument. */
3395 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3396 startline = atoi(&argv[optind][1]);
3397 optind++;
3398 }
3399 if (0 < optind && optind < argc)
3400 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003401
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003402 /* See if there's a non-option in argv (first non-option is the
3403 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003404 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003405 /* Look for the +line flag... */
3406 if (argv[optind][0] == '+') {
3407 startline = atoi(&argv[optind][1]);
3408 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003409 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003410 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003411 } else
3412 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003413 }
3414
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003415 /* Termios initialization stuff: Back up the old settings so that
3416 * they can be restored, disable SIGINT on ^C and SIGQUIT on ^\,
3417 * since we need them for Cancel and Replace, and disable
3418 * implementation-defined input processing. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003419 tcgetattr(0, &oldterm);
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003420#ifdef _POSIX_VDISABLE
3421 term = oldterm;
3422 term.c_cc[VINTR] = _POSIX_VDISABLE;
3423 term.c_cc[VQUIT] = _POSIX_VDISABLE;
3424 term.c_lflag &= ~IEXTEN;
3425 tcsetattr(0, TCSANOW, &term);
3426#endif
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003427
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003428 /* Curses initialization stuff: Start curses, save the state of the
3429 * the terminal mode, disable translation of carriage return (^M)
3430 * into newline (^J) so we can catch the Enter key and use ^J for
3431 * Justify, turn the keypad on for the windows that read input, put
3432 * the terminal in cbreak mode (read one character at a time and
3433 * interpret the special control keys) if we can selectively disable
3434 * the special control keys or raw mode (read one character at a
3435 * time and don't interpret the special control keys) if we
3436 * can't, and turn off echoing of characters as they're typed. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003437 initscr();
3438 savetty();
3439 nonl();
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003440 keypad(edit, TRUE);
3441 keypad(bottomwin, TRUE);
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00003442#ifdef _POSIX_VDISABLE
3443 cbreak();
3444#else
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003445 raw();
3446#endif
David Lawrence Ramseyd03216a2004-01-28 18:21:21 +00003447 noecho();
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003448
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003449 /* Set up the global variables and the shortcuts. */
Chris Allegretta56214c62001-09-27 02:46:53 +00003450 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003451 shortcut_init(0);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003452
3453 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003454 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003455
3456#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003457 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003458#endif
3459
Chris Allegretta2a42af12000-09-12 23:02:49 +00003460 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003461#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003462 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003463#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003464
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003465#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003466 fprintf(stderr, "Main: bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003467#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003468 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003469 display_main_list();
3470
3471#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003472 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003473#endif
3474
Chris Allegretta3d459ad2003-01-22 01:09:40 +00003475 open_file(filename, 0, 1);
Chris Allegretta7662c862003-01-13 01:35:15 +00003476#ifdef ENABLE_MULTIBUFFER
3477 /* If we're using multibuffers and more than one file is specified
3478 on the command line, load them all and switch to the first one
3479 afterward */
3480 if (ISSET(MULTIBUFFER) && optind + 1 < argc) {
3481 for (optind++; optind < argc; optind++) {
3482 add_open_file(1);
3483 new_file();
3484 filename = mallocstrcpy(filename, argv[optind]);
3485 open_file(filename, 0, 0);
3486 load_file(0);
3487 }
3488 open_nextfile_void();
3489 }
3490#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003491
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003492 titlebar(NULL);
3493
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003494 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003495 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003496
Chris Allegretta7662c862003-01-13 01:35:15 +00003497 /* Return here after a sigwinch */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003498 sigsetjmp(jmpbuf, 1);
Chris Allegretta08020882001-01-29 23:37:54 +00003499
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003500 /* SHUT UP GCC! */
3501 startline = 0;
3502 fill_flag_used = 0;
3503 keyhandled = 0;
3504
Chris Allegretta7662c862003-01-13 01:35:15 +00003505 /* This variable should be initialized after the sigsetjmp(), so we
3506 can't do Esc-Esc then quickly resize and muck things up. */
Chris Allegretta08020882001-01-29 23:37:54 +00003507 modify_control_seq = 0;
3508
Robert Siemborski6967eec2000-07-08 14:23:32 +00003509 edit_refresh();
3510 reset_cursor();
3511
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003512 while (TRUE) {
Chris Allegrettad0845df2003-02-13 00:56:57 +00003513 keyhandled = 0;
Chris Allegretta9239d742000-09-06 15:19:18 +00003514
Chris Allegrettad26ab912003-01-28 01:16:47 +00003515 if (ISSET(CONSTUPDATE))
3516 do_cursorpos(1);
3517
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003518#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003519 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003520#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003521
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003522 kbinput = get_kbinput(edit, &meta_key);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003523#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003524 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003525#endif
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003526 if (meta_key == TRUE) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003527 /* Check for the metaval and miscval defs... */
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003528 for (s = main_list; s != NULL; s = s->next)
David Lawrence Ramsey82138502003-12-24 08:03:54 +00003529 if ((s->metaval != NANO_NO_KEY && kbinput == s->metaval) ||
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003530 (s->miscval != NANO_NO_KEY && kbinput == s->miscval)) {
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003531 if (ISSET(VIEW_MODE) && !s->viewok)
3532 print_view_warning();
3533 else {
3534 if (s->func != do_cut_text)
3535 UNSET(KEEP_CUTBUFFER);
3536 s->func();
3537 }
3538 keyhandled = 1;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003539 }
3540#ifndef NANO_SMALL
3541 if (!keyhandled)
3542 /* And for toggle switches */
3543 for (t = toggles; t != NULL; t = t->next)
3544 if (kbinput == t->val) {
3545 UNSET(KEEP_CUTBUFFER);
3546 do_toggle(t);
3547 keyhandled = 1;
3548 }
3549#endif
3550#ifdef DEBUG
3551 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput,
3552 kbinput);
3553#endif
3554 }
3555
3556 /* Look through the main shortcut list to see if we've hit a
3557 shortcut key or function key */
3558
3559 if (!keyhandled)
3560#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
3561 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
3562#else
3563 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
3564#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003565 if ((s->ctrlval != NANO_NO_KEY && kbinput == s->ctrlval) ||
3566 (s->funcval != NANO_NO_KEY && kbinput == s->funcval)) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003567 if (ISSET(VIEW_MODE) && !s->viewok)
3568 print_view_warning();
3569 else {
3570 if (s->func != do_cut_text)
3571 UNSET(KEEP_CUTBUFFER);
3572 s->func();
3573 }
3574 keyhandled = 1;
3575 /* Break out explicitly once we successfully handle
3576 a shortcut */
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003577 break;
3578 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003579 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003580
3581 if (!keyhandled)
3582 UNSET(KEEP_CUTBUFFER);
Chris Allegrettae42df732002-10-15 00:27:55 +00003583
3584#ifdef _POSIX_VDISABLE
3585 /* Don't even think about changing this string */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003586 if (kbinput == NANO_CONTROL_Q)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003587 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003588 if (kbinput == NANO_CONTROL_S)
3589 statusbar(_("XOFF ignored, mumble mumble."));
Chris Allegrettae42df732002-10-15 00:27:55 +00003590#endif
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003591 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3592 Control-S and Control-Q */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003593 if (kbinput == NANO_CONTROL_Q || kbinput == NANO_CONTROL_S)
Chris Allegretta9239d742000-09-06 15:19:18 +00003594 keyhandled = 1;
3595
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003596 /* Catch ^Z by hand when triggered also */
3597 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003598 if (ISSET(SUSPEND))
3599 do_suspend(0);
3600 keyhandled = 1;
3601 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003602
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003603 /* Last gasp, stuff that's not in the main lists */
3604 if (!keyhandled)
3605 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003606#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003607 case KEY_MOUSE:
3608 do_mouse();
3609 break;
3610#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003611
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003612 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3613 * have been handled before we
3614 * got here */
3615 case NANO_CONTROL_5: /* Ctrl-] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003616 break;
3617 default:
3618#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003619 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003620#endif
3621 /* We no longer stop unhandled sequences so that people with
3622 odd character sets can type... */
3623
Chris Allegretta7662c862003-01-13 01:35:15 +00003624 if (ISSET(VIEW_MODE))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003625 print_view_warning();
Chris Allegretta7662c862003-01-13 01:35:15 +00003626 else
3627 do_char(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003628 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003629
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003630 reset_cursor();
3631 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003632 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003633 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003634}