blob: ac55a3a43d2aac54e0b424cefbb4a71e61ab3cf3 [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>
28#include <unistd.h>
29#include <string.h>
30#include <fcntl.h>
31#include <sys/stat.h>
32#include <sys/ioctl.h>
33#include <sys/param.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000034#include <sys/types.h>
35#include <sys/wait.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000036#include <errno.h>
37#include <ctype.h>
38#include <locale.h>
39#include <limits.h>
Adam Rogoyski77f36de2000-06-07 03:56:54 +000040#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000041#include "proto.h"
42#include "nano.h"
43
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000044#ifdef HAVE_TERMIOS_H
45#include <termios.h>
46#endif
47
48#ifdef HAVE_TERMIO_H
49#include <termio.h>
50#endif
51
52#ifdef HAVE_GETOPT_H
53#include <getopt.h>
54#endif
55
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000056#ifndef NANO_SMALL
57#include <setjmp.h>
58#endif
59
Chris Allegretta6fe61492001-05-21 12:56:25 +000060#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +000061static int fill = 0; /* Fill - where to wrap lines, basically */
Chris Allegretta6fe61492001-05-21 12:56:25 +000062#endif
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000063#ifndef DISABLE_WRAPPING
64static int same_line_wrap = 0; /* Whether wrapped text should be
65 prepended to the next line */
66#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000067
Chris Allegretta6df90f52002-07-19 01:08:59 +000068static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000069static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000070
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000071#ifndef NANO_SMALL
Chris Allegretta08020882001-01-29 23:37:54 +000072static sigjmp_buf jmpbuf; /* Used to return to mainloop after SIGWINCH */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000073#endif
Chris Allegretta08020882001-01-29 23:37:54 +000074
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000075/* What we do when we're all set to exit */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +000076RETSIGTYPE finish(int sigage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000077{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000078 if (!ISSET(NO_HELP))
79 blank_bottombars();
80 else
81 blank_statusbar();
Chris Allegretta6b58acd2001-04-12 03:01:53 +000082
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000083 wrefresh(bottomwin);
84 endwin();
85
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000086 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000087 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000088
Chris Allegrettad8451932003-03-11 03:50:40 +000089#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
90 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
91 save_history();
92#endif
93
Chris Allegretta6232d662002-05-12 19:52:15 +000094#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000095 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +000096#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000097
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000098 exit(sigage);
99}
100
101/* Die (gracefully?) */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000102void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000103{
104 va_list ap;
105
Chris Allegrettaa0d89972003-02-03 03:32:08 +0000106 endwin();
107 curses_ended = TRUE;
108
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000109 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000110 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000111
Chris Allegretta6df90f52002-07-19 01:08:59 +0000112 va_start(ap, msg);
113 vfprintf(stderr, msg, ap);
114 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000115
Chris Allegretta32da4562002-01-02 15:12:21 +0000116 /* save the currently loaded file if it's been modified */
117 if (ISSET(MODIFIED))
118 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000119
Chris Allegretta355fbe52001-07-14 19:32:47 +0000120#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000121 /* then save all of the other modified loaded files, if any */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000122 if (open_files != NULL) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000123 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000124
125 tmp = open_files;
126
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000127 while (open_files->prev != NULL)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000128 open_files = open_files->prev;
129
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000130 while (open_files->next != NULL) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000131
David Lawrence Ramseya3370c42004-04-05 01:08:14 +0000132 /* if we already saved the file above (i.e, if it was the
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000133 currently loaded file), don't save it again */
134 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000135 /* make sure open_files->fileage and fileage, and
136 open_files->filebot and filebot, are in sync; they
137 might not be if lines have been cut from the top or
138 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000139 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000140 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000141 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000142 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000143 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000144 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000145 open_files = open_files->next;
146 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000147 }
148#endif
149
Chris Allegretta6df90f52002-07-19 01:08:59 +0000150 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000151}
152
Chris Allegretta6df90f52002-07-19 01:08:59 +0000153void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000154{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000155 char *ret;
Chris Allegretta48b06702002-02-22 04:30:50 +0000156 int i = -1;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000157
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000158 /* No emergency files in restricted mode! */
159 if (ISSET(RESTRICTED))
160 return;
161
Chris Allegretta6df90f52002-07-19 01:08:59 +0000162 /* If we can't save, we have REAL bad problems, but we might as well
163 TRY. */
164 if (die_filename[0] == '\0')
165 ret = get_next_filename("nano.save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000166 else {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000167 char *buf = charalloc(strlen(die_filename) + 6);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000168
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000169 strcpy(buf, die_filename);
170 strcat(buf, ".save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000171 ret = get_next_filename(buf);
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000172 free(buf);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000173 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000174 if (ret[0] != '\0')
175 i = write_file(ret, 1, 0, 0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000176
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000177 if (i != -1)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000178 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000179 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000180 fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000181
182 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000183}
184
Chris Allegrettae61e8302001-01-14 05:18:27 +0000185/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000186 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000187void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000188{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000189 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000190}
191
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000192void print_view_warning(void)
193{
194 statusbar(_("Key illegal in VIEW mode"));
195}
196
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +0000197/* Initialize global variables -- no better way for now. If
Chris Allegretta6df90f52002-07-19 01:08:59 +0000198 * save_cutbuffer is nonzero, don't set cutbuffer to NULL. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000199void global_init(int save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000200{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000201 current_x = 0;
202 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000203
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000204 editwinrows = LINES - 5 + no_help();
205 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000206 die_too_small();
207
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000208 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000209 if (!save_cutbuffer)
210 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000211 current = NULL;
212 edittop = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000213 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000214 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000215 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000216
Chris Allegretta6fe61492001-05-21 12:56:25 +0000217#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000218 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000219 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000220 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000221 if (fill < 0)
222 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000223#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000224
Chris Allegretta88b09152001-05-17 11:35:43 +0000225 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000226 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000227 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000228}
229
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000230void window_init(void)
231{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000232 editwinrows = LINES - 5 + no_help();
233 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000234 die_too_small();
235
Chris Allegretta1a128af2003-01-26 04:15:56 +0000236 if (topwin != NULL)
237 delwin(topwin);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000238 if (edit != NULL)
239 delwin(edit);
Chris Allegretta1a128af2003-01-26 04:15:56 +0000240 if (bottomwin != NULL)
241 delwin(bottomwin);
242
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000243 /* Set up the windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000244 topwin = newwin(2, COLS, 0, 0);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000245 edit = newwin(editwinrows, COLS, 2, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000246 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
247
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000248 /* Turn the keypad back on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000249 keypad(edit, TRUE);
250 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000251}
252
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000253#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000254void mouse_init(void)
255{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000256 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000257 mousemask(BUTTON1_RELEASED, NULL);
258 mouseinterval(50);
259 } else
260 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000261}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000262#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000263
264#ifndef DISABLE_HELP
265/* This function allocates help_text, and stores the help string in it.
266 * help_text should be NULL initially. */
267void help_init(void)
268{
Chris Allegretta908f7702003-01-15 11:18:58 +0000269 size_t allocsize = 1; /* space needed for help_text */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000270 char *ptr = NULL;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000271 const shortcut *s;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000272#ifndef NANO_SMALL
273 const toggle *t;
274#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000275
276 /* First set up the initial help text for the current function */
277 if (currshortcut == whereis_list || currshortcut == replace_list
278 || currshortcut == replace_list_2)
279 ptr = _("Search Command Help Text\n\n "
280 "Enter the words or characters you would like to search "
281 "for, then hit enter. If there is a match for the text you "
282 "entered, the screen will be updated to the location of the "
283 "nearest match for the search string.\n\n "
Chris Allegretta37d594c2003-01-05 22:00:41 +0000284 "The previous search string will be shown in brackets after "
285 "the Search: prompt. Hitting Enter without entering any text "
286 "will perform the previous search.\n\n The following function "
287 "keys are available in Search mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000288 else if (currshortcut == goto_list)
289 ptr = _("Go To Line Help Text\n\n "
290 "Enter the line number that you wish to go to and hit "
291 "Enter. If there are fewer lines of text than the "
292 "number you entered, you will be brought to the last line "
293 "of the file.\n\n The following function keys are "
294 "available in Go To Line mode:\n\n");
295 else if (currshortcut == insertfile_list)
296 ptr = _("Insert File Help Text\n\n "
297 "Type in the name of a file to be inserted into the current "
298 "file buffer at the current cursor location.\n\n "
299 "If you have compiled nano with multiple file buffer "
300 "support, and enable multiple buffers with the -F "
301 "or --multibuffer command line flags, the Meta-F toggle, or "
302 "a nanorc file, inserting a file will cause it to be "
303 "loaded into a separate buffer (use Meta-< and > to switch "
304 "between file buffers).\n\n If you need another blank "
305 "buffer, do not enter any filename, or type in a "
306 "nonexistent filename at the prompt and press "
307 "Enter.\n\n The following function keys are "
308 "available in Insert File mode:\n\n");
309 else if (currshortcut == writefile_list)
310 ptr = _("Write File Help Text\n\n "
311 "Type the name that you wish to save the current file "
312 "as and hit Enter to save the file.\n\n If you have "
313 "selected text with Ctrl-^, you will be prompted to "
314 "save only the selected portion to a separate file. To "
315 "reduce the chance of overwriting the current file with "
316 "just a portion of it, the current filename is not the "
317 "default in this mode.\n\n The following function keys "
318 "are available in Write File mode:\n\n");
319#ifndef DISABLE_BROWSER
320 else if (currshortcut == browser_list)
321 ptr = _("File Browser Help Text\n\n "
322 "The file browser is used to visually browse the "
323 "directory structure to select a file for reading "
324 "or writing. You may use the arrow keys or Page Up/"
325 "Down to browse through the files, and S or Enter to "
326 "choose the selected file or enter the selected "
327 "directory. To move up one level, select the directory "
328 "called \"..\" at the top of the file list.\n\n The "
329 "following function keys are available in the file "
330 "browser:\n\n");
331 else if (currshortcut == gotodir_list)
332 ptr = _("Browser Go To Directory Help Text\n\n "
333 "Enter the name of the directory you would like to "
334 "browse to.\n\n If tab completion has not been disabled, "
335 "you can use the TAB key to (attempt to) automatically "
336 "complete the directory name.\n\n The following function "
337 "keys are available in Browser Go To Directory mode:\n\n");
338#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000339#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000340 else if (currshortcut == spell_list)
341 ptr = _("Spell Check Help Text\n\n "
342 "The spell checker checks the spelling of all text "
343 "in the current file. When an unknown word is "
344 "encountered, it is highlighted and a replacement can "
345 "be edited. It will then prompt to replace every "
346 "instance of the given misspelled word in the "
347 "current file.\n\n The following other functions are "
348 "available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000349#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000350#ifndef NANO_SMALL
351 else if (currshortcut == extcmd_list)
352 ptr = _("External Command Help Text\n\n "
353 "This menu allows you to insert the output of a command "
354 "run by the shell into the current buffer (or a new "
355 "buffer in multibuffer mode).\n\n The following keys are "
356 "available in this mode:\n\n");
357#endif
358 else /* Default to the main help list */
359 ptr = _(" nano help text\n\n "
360 "The nano editor is designed to emulate the functionality and "
361 "ease-of-use of the UW Pico text editor. There are four main "
362 "sections of the editor: The top line shows the program "
363 "version, the current filename being edited, and whether "
364 "or not the file has been modified. Next is the main editor "
365 "window showing the file being edited. The status line is "
366 "the third line from the bottom and shows important messages. "
367 "The bottom two lines show the most commonly used shortcuts "
368 "in the editor.\n\n "
369 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000370 "sequences are notated with a caret (^) symbol and can be "
371 "entered either by using the Control (Ctrl) key or pressing the "
372 "Esc key twice. Escape-key sequences are notated with the Meta "
373 "(M) symbol and can be entered using either the Esc, Alt or "
374 "Meta key depending on your keyboard setup. Also, pressing Esc "
375 "twice and then typing a three-digit number from 000 to 255 "
376 "will enter the character with the corresponding ASCII code. "
377 "The following keystrokes are available in the main editor "
378 "window. Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000379
Chris Allegretta908f7702003-01-15 11:18:58 +0000380 allocsize += strlen(ptr);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000381
382 /* The space needed for the shortcut lists, at most COLS characters,
383 * plus '\n'. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000384 allocsize += (COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000385
386#ifndef NANO_SMALL
387 /* If we're on the main list, we also count the toggle help text.
388 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
389 * COLS - 24 characters, plus '\n'.*/
Chris Allegretta3a784062003-02-10 02:32:58 +0000390 if (currshortcut == main_list) {
391 size_t endislen = strlen(_("enable/disable"));
392
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000393 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000394 allocsize += 8 + strlen(t->desc) + endislen;
395 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000396#endif /* !NANO_SMALL */
397
398 /* help_text has been freed and set to NULL unless the user resized
399 * while in the help screen. */
400 free(help_text);
401
402 /* Allocate space for the help text */
Chris Allegretta908f7702003-01-15 11:18:58 +0000403 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000404
405 /* Now add the text we want */
406 strcpy(help_text, ptr);
407 ptr = help_text + strlen(help_text);
408
409 /* Now add our shortcut info */
410 for (s = currshortcut; s != NULL; s = s->next) {
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000411 /* true if the character in s->metaval is shown in first column */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000412 int meta_shortcut = 0;
413
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000414 if (s->ctrlval != NANO_NO_KEY) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000415#ifndef NANO_SMALL
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000416 if (s->ctrlval == NANO_HISTORY_KEY)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000417 ptr += sprintf(ptr, "%.2s", _("Up"));
418 else
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000419#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000420 if (s->ctrlval == NANO_CONTROL_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000421 ptr += sprintf(ptr, "^%.5s", _("Space"));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000422 else if (s->ctrlval == NANO_CONTROL_8)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000423 ptr += sprintf(ptr, "^?");
424 else
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000425 ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000426 }
427#ifndef NANO_SMALL
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000428 else if (s->metaval != NANO_NO_KEY) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000429 meta_shortcut = 1;
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000430 if (s->metaval == NANO_ALT_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000431 ptr += snprintf(ptr, 8, "M-%.5s", _("Space"));
432 else
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000433 ptr += sprintf(ptr, "M-%c", toupper(s->metaval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000434 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000435#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000436
437 *(ptr++) = '\t';
438
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000439 if (s->funcval != NANO_NO_KEY)
440 ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000441
442 *(ptr++) = '\t';
443
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000444 if (!meta_shortcut && s->metaval != NANO_NO_KEY)
445 ptr += sprintf(ptr, "(M-%c)", toupper(s->metaval));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000446 else if (meta_shortcut && s->miscval != NANO_NO_KEY)
447 ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000448
449 *(ptr++) = '\t';
450
451 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000452 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000453 }
454
455#ifndef NANO_SMALL
456 /* And the toggles... */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000457 if (currshortcut == main_list) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000458 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000459 assert(t->desc != NULL);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000460 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val), t->desc,
Chris Allegretta3a784062003-02-10 02:32:58 +0000461 _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000462 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000463 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000464#endif /* !NANO_SMALL */
465
466 /* If all went well, we didn't overwrite the allocated space for
467 help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000468 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000469}
470#endif
471
472/* Create a new filestruct node. Note that we specifically do not set
473 * prevnode->next equal to the new line. */
474filestruct *make_new_node(filestruct *prevnode)
475{
476 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
477
478 newnode->data = NULL;
479 newnode->prev = prevnode;
480 newnode->next = NULL;
481 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
482
483 return newnode;
484}
485
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000486/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000487filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000488{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000489 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000490
Chris Allegretta6df90f52002-07-19 01:08:59 +0000491 assert(src != NULL);
492
Chris Allegretta88b09152001-05-17 11:35:43 +0000493 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000494 dst->next = src->next;
495 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000496 strcpy(dst->data, src->data);
497 dst->lineno = src->lineno;
498
499 return dst;
500}
501
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000502/* Splice a node into an existing filestruct. */
503void splice_node(filestruct *begin, filestruct *newnode, filestruct *end)
504{
505 if (newnode != NULL) {
506 newnode->next = end;
507 newnode->prev = begin;
508 }
509 if (begin != NULL)
510 begin->next = newnode;
511 if (end != NULL)
512 end->prev = newnode;
513}
514
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000515/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000516void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000517{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000518 assert(fileptr != NULL);
519
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000520 if (fileptr->prev != NULL)
521 fileptr->prev->next = fileptr->next;
522
523 if (fileptr->next != NULL)
524 fileptr->next->prev = fileptr->prev;
525}
526
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000527/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000528void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000529{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000530 if (fileptr != NULL) {
531 if (fileptr->data != NULL)
532 free(fileptr->data);
533 free(fileptr);
534 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000535}
536
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000537/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000538filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000539{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000540 filestruct *head; /* copy of src, top of the copied list */
541 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000542
Chris Allegretta6df90f52002-07-19 01:08:59 +0000543 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000544
Chris Allegretta6df90f52002-07-19 01:08:59 +0000545 prev = copy_node(src);
546 prev->prev = NULL;
547 head = prev;
548 src = src->next;
549 while (src != NULL) {
550 prev->next = copy_node(src);
551 prev->next->prev = prev;
552 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000553
Chris Allegretta6df90f52002-07-19 01:08:59 +0000554 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000555 }
556
Chris Allegretta6df90f52002-07-19 01:08:59 +0000557 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000558 return head;
559}
560
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000561/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000562void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000563{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000564 if (src != NULL) {
565 while (src->next != NULL) {
566 src = src->next;
567 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000568#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000569 fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_node()");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000570#endif
571 }
572 delete_node(src);
573#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000574 fprintf(stderr, "%s: free'd last node.\n", "delete_node()");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000575#endif
576 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000577}
578
Chris Allegretta6df90f52002-07-19 01:08:59 +0000579void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000580{
581 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000582 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000583
Chris Allegretta6df90f52002-07-19 01:08:59 +0000584 assert(fileage == NULL || fileage != fileage->next);
585 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000586 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000587}
588
Chris Allegretta6df90f52002-07-19 01:08:59 +0000589void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000590{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000591 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000592 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000593 else {
594 int lineno = fileptr->prev->lineno;
595
596 assert(fileptr != fileptr->next);
597 for (; fileptr != NULL; fileptr = fileptr->next)
598 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000599 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000600}
601
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000602/* Print one usage string to the screen, removes lots of duplicate
Chris Allegretta6df90f52002-07-19 01:08:59 +0000603 * strings to translate and takes out the parts that shouldn't be
604 * translatable (the flag names). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000605void print1opt(const char *shortflag, const char *longflag,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000606 const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000607{
608 printf(" %s\t", shortflag);
609 if (strlen(shortflag) < 8)
610 printf("\t");
611
612#ifdef HAVE_GETOPT_LONG
613 printf("%s\t", longflag);
614 if (strlen(longflag) < 8)
615 printf("\t\t");
616 else if (strlen(longflag) < 16)
617 printf("\t");
618#endif
619
620 printf("%s\n", desc);
621}
622
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000623void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000624{
625#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000626 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
627 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000628#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000629 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
630 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000631#endif /* HAVE_GETOPT_LONG */
632
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000633 print1opt("-h, -?", "--help", _("Show this message"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000634 print1opt(_("+LINE"), "", _("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000635#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000636 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000637 print1opt("-D", "--dos", _("Write file in DOS format"));
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +0000638 print1opt("-E", "--backupdir=[dir]", _("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000639#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000640#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000641 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000642#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000643#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000644#ifndef NANO_SMALL
Chris Allegretta36fec722003-01-22 01:13:25 +0000645 print1opt("-H", "--historylog", _("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000646#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000647 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
648#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000649#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000650 print1opt("-M", "--mac", _("Write file in Mac format"));
651 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000652#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000653#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000654 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000655#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000656#ifdef HAVE_REGEX_H
657 print1opt("-R", "--regexp", _("Do regular expression searches"));
658#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000659#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000660 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000661#endif
David Lawrence Ramseya7c93642004-02-25 03:19:29 +0000662 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), _("Set width of a tab in cols to #cols"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000663 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000664#ifdef ENABLE_COLOR
665 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
666#endif
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000667 print1opt(_("-Z"), _("--restricted"), _("Restricted mode"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000668 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000669#ifndef NANO_SMALL
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000670 print1opt("-d", "--rebinddelete", _("Fix Backspace/Delete confusion problem"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000671 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
672 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000673#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000674 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000675#ifndef DISABLE_MOUSE
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000676 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000677#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000678#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000679 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000680#endif
Jordi Mallacheeb50042003-01-18 22:42:34 +0000681 print1opt("-p", "--preserve", _("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000682#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000683 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000684#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000685#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000686 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000687#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000688 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
689 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000690#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000691 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000692#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000693 print1opt("-x", "--nohelp", _("Don't show help window"));
694 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000695
696 /* this is a special case */
697 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000698
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000699 exit(0);
700}
701
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000702void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000703{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000704 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000705 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000706 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000707 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000708 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000709
Chris Allegrettae6600372003-01-17 03:39:41 +0000710#ifndef ENABLE_NLS
711 printf(" --disable-nls");
712#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000713#ifdef DEBUG
714 printf(" --enable-debug");
715#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000716#ifdef NANO_EXTRA
717 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000718#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000719#ifdef NANO_SMALL
720 printf(" --enable-tiny");
721#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000722#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000723 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000724#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000725#ifdef DISABLE_HELP
726 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000727#endif
728#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000729 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000730#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000731#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +0000732 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000733#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000734#ifdef DISABLE_OPERATINGDIR
735 printf(" --disable-operatingdir");
736#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000737#ifdef DISABLE_SPELLER
738 printf(" --disable-speller");
739#endif
740#ifdef DISABLE_TABCOMP
741 printf(" --disable-tabcomp");
742#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000743#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000744#ifdef DISABLE_WRAPPING
745 printf(" --disable-wrapping");
746#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000747#ifdef DISABLE_ROOTWRAP
748 printf(" --disable-wrapping-as-root");
749#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000750#ifdef ENABLE_COLOR
751 printf(" --enable-color");
752#endif
753#ifdef ENABLE_MULTIBUFFER
754 printf(" --enable-multibuffer");
755#endif
756#ifdef ENABLE_NANORC
757 printf(" --enable-nanorc");
758#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000759#ifdef USE_SLANG
760 printf(" --with-slang");
761#endif
762 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000763}
764
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000765int 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
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000770int nano_disabled_msg(void)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000771{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000772 statusbar(_("Sorry, support for this function has been disabled"));
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000773 return 1;
Chris Allegrettaff269f82000-12-01 18:46:01 +0000774}
775
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000776#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000777static int pid; /* This is the PID of the newly forked process
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000778 * below. It must be global since the signal
779 * handler needs it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000780RETSIGTYPE cancel_fork(int signal)
781{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000782 if (kill(pid, SIGKILL) == -1)
783 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000784}
785
786int open_pipe(const char *command)
787{
788 int fd[2];
789 FILE *f;
790 struct sigaction oldaction, newaction;
791 /* original and temporary handlers for SIGINT */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000792 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000793 /* cancel_sigs == 1 means that sigaction() failed without changing
794 * the signal handlers. cancel_sigs == 2 means the signal handler
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000795 * was changed, but the tcsetattr() didn't succeed.
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000796 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000797 * I use this variable since it is important to put things back when
798 * we finish, even if we get errors. */
799
800 /* Make our pipes. */
801
802 if (pipe(fd) == -1) {
803 statusbar(_("Could not pipe"));
804 return 1;
805 }
806
807 /* Fork a child. */
808
809 if ((pid = fork()) == 0) {
810 close(fd[0]);
811 dup2(fd[1], fileno(stdout));
812 dup2(fd[1], fileno(stderr));
813 /* If execl() returns at all, there was an error. */
814
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000815 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000816 exit(0);
817 }
818
819 /* Else continue as parent. */
820
821 close(fd[1]);
822
823 if (pid == -1) {
824 close(fd[0]);
825 statusbar(_("Could not fork"));
826 return 1;
827 }
828
829 /* Before we start reading the forked command's output, we set
830 * things up so that ^C will cancel the new process. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000831
832 enable_signals();
833
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000834 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000835 cancel_sigs = 1;
836 nperror("sigaction");
837 } else {
838 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000839 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000840 cancel_sigs = 1;
841 nperror("sigaction");
842 }
843 }
844 /* Note that now oldaction is the previous SIGINT signal handler,
845 * to be restored later. */
846
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000847 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000848 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000849 nperror("fdopen");
850
851 read_file(f, "stdin", 0);
852 /* if multibuffer mode is on, we could be here in view mode; if so,
853 don't set the modification flag */
854 if (!ISSET(VIEW_MODE))
855 set_modified();
856
857 if (wait(NULL) == -1)
858 nperror("wait");
859
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000860 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000861 nperror("sigaction");
862
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000863 disable_signals();
864
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000865 return 0;
866}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +0000867#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000868
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000869#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000870void do_mouse(void)
871{
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000872 int mouse_x, mouse_y;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000873
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000874 if (get_mouseinput(&mouse_x, &mouse_y, 1) == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000875
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000876 /* Click in the edit window to move the cursor, but only when
877 we're not in a subfunction. */
878 if (wenclose(edit, mouse_y, mouse_x) && currshortcut == main_list) {
879 int sameline;
880 /* Did they click on the line with the cursor? If they
881 clicked on the cursor, we set the mark. */
882 size_t xcur;
883 /* The character they clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000884
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000885 /* Subtract out size of topwin. Perhaps we need a constant
886 somewhere? */
887 mouse_y -= 2;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000888
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000889 sameline = (mouse_y == current_y);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000890
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000891 /* Move to where the click occurred. */
892 for (; current_y < mouse_y && current->next != NULL; current_y++)
893 current = current->next;
894 for (; current_y > mouse_y && current->prev != NULL; current_y--)
895 current = current->prev;
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000896
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000897 xcur = actual_x(current->data, get_page_start(xplustabs()) +
898 mouse_x);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000899
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000900 /* Selecting where the cursor is toggles the mark. As does
901 selecting beyond the line length with the cursor at the
902 end of the line. */
903 if (sameline && xcur == current_x) {
904 if (ISSET(VIEW_MODE)) {
905 print_view_warning();
906 return;
907 }
908 do_mark();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000909 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000910
911 current_x = xcur;
912 placewewant = xplustabs();
913 edit_refresh();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000914 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000915 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000916 /* FIXME: If we clicked on a location in the statusbar, the cursor
917 should move to the location we clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000918}
919#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000920
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000921/* The user typed a character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000922void do_char(char ch)
923{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000924 size_t current_len = strlen(current->data);
925#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey604caf32004-04-19 02:44:13 +0000926 int refresh = FALSE;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000927 /* Do we have to run edit_refresh(), or can we get away with
928 * update_line()? */
929#endif
930
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000931 if (ch == '\0') /* Null to newline, if needed. */
932 ch = '\n';
933 else if (ch == '\n') { /* Newline to Enter, if needed. */
934 do_enter();
935 return;
936 }
937
938 assert(current != NULL && current->data != NULL);
939
940 /* When a character is inserted on the current magicline, it means
941 * we need a new one! */
David Lawrence Ramseyb9775152004-03-19 02:15:42 +0000942 if (filebot == current)
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000943 new_magicline();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000944
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000945 /* More dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000946 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000947 assert(current_x <= current_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000948 charmove(&current->data[current_x + 1], &current->data[current_x],
949 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000950 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000951 totsize++;
952 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000953
Chris Allegretta6df90f52002-07-19 01:08:59 +0000954#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000955 /* Note that current_x has not yet been incremented. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000956 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000957 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +0000958#endif
959
Chris Allegretta6df90f52002-07-19 01:08:59 +0000960 do_right();
961
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000962#ifndef DISABLE_WRAPPING
Chris Allegrettadffa2072002-07-24 01:02:26 +0000963 if (!ISSET(NO_WRAP) && ch != '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +0000964 refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000965#endif
966
Chris Allegretta6df90f52002-07-19 01:08:59 +0000967#ifdef ENABLE_COLOR
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +0000968 if (ISSET(COLOR_SYNTAX))
David Lawrence Ramsey604caf32004-04-19 02:44:13 +0000969 refresh = TRUE;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000970#endif
971
972#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
973 if (refresh)
974 edit_refresh();
975#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000976}
977
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000978int do_verbatim_input(void)
979{
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000980 int *verbatim_kbinput; /* Used to hold verbatim input. */
David Lawrence Ramsey805547f2004-04-22 03:41:04 +0000981 size_t verbatim_len; /* Length of verbatim input. */
982 size_t i;
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000983
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000984 statusbar(_("Verbatim input"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000985 verbatim_kbinput = get_verbatim_kbinput(edit, &verbatim_len, 1);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000986
987 /* Turn on DISABLE_CURPOS while inserting character(s) and turn it
988 * off afterwards, so that if constant cursor position display is
989 * on, it will be updated properly. */
990 SET(DISABLE_CURPOS);
991 for (i = 0; i < verbatim_len; i++)
David Lawrence Ramsey815cba82004-02-07 03:07:01 +0000992 do_char((char)verbatim_kbinput[i]);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000993 UNSET(DISABLE_CURPOS);
994
995 free(verbatim_kbinput);
996
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000997 return 1;
998}
999
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001000int do_backspace(void)
1001{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001002 if (current != fileage || current_x > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001003 do_left();
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001004 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001005 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001006 return 1;
1007}
1008
1009int do_delete(void)
1010{
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001011 assert(current != NULL && current->data != NULL && current_x <=
1012 strlen(current->data));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001013
1014 placewewant = xplustabs();
1015
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001016 if (current->data[current_x] != '\0') {
1017 size_t linelen = strlen(current->data + current_x);
1018
1019 assert(current_x < strlen(current->data));
1020
1021 /* Let's get dangerous. */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001022 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001023 linelen);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001024
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001025 null_at(&current->data, linelen + current_x - 1);
1026#ifndef NANO_SMALL
1027 if (current_x < mark_beginx && mark_beginbuf == current)
1028 mark_beginx--;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001029#endif
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001030 } else if (current != filebot && (current->next != filebot ||
1031 current->data[0] == '\0')) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001032 /* We can delete the line before filebot only if it is blank: it
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001033 * becomes the new magic line then. */
1034 filestruct *foo = current->next;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001035
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001036 assert(current_x == strlen(current->data));
1037 current->data = charealloc(current->data, current_x +
1038 strlen(foo->data) + 1);
1039 strcpy(current->data + current_x, foo->data);
1040#ifndef NANO_SMALL
1041 if (mark_beginbuf == current->next) {
1042 mark_beginx += current_x;
1043 mark_beginbuf = current;
1044 }
1045#endif
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001046 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001047 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001048
1049 unlink_node(foo);
1050 delete_node(foo);
1051 renumber(current);
1052 totlines--;
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001053 wrap_reset();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001054 } else
1055 return 0;
1056
1057 totsize--;
1058 set_modified();
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001059 edit_refresh();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001060 return 1;
1061}
1062
1063int do_tab(void)
1064{
1065 do_char('\t');
1066 return 1;
1067}
1068
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001069/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001070int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001071{
Chris Allegrettae3167732001-03-18 16:59:34 +00001072 filestruct *newnode;
Chris Allegretta68532c32001-09-17 13:49:33 +00001073 char *tmp;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001074
Chris Allegretta6df90f52002-07-19 01:08:59 +00001075 newnode = make_new_node(current);
1076 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001077 tmp = &current->data[current_x];
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001078
Chris Allegrettaff989832001-09-17 13:48:00 +00001079#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001080 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001081 if (ISSET(AUTOINDENT)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001082 int extra = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001083 const char *spc = current->data;
1084
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001085 while (isblank(*spc)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001086 extra++;
1087 spc++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001088 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001089 /* If current_x < extra, then we are breaking the line in the
1090 * indentation. Autoindenting should add only current_x
1091 * characters of indentation. */
Chris Allegrettadab017e2002-04-23 10:56:06 +00001092 if (current_x < extra)
1093 extra = current_x;
1094 else
1095 current_x = extra;
1096 totsize += extra;
1097
1098 newnode->data = charalloc(strlen(tmp) + extra + 1);
1099 strncpy(newnode->data, current->data, extra);
1100 strcpy(&newnode->data[extra], tmp);
Chris Allegrettaff989832001-09-17 13:48:00 +00001101 } else
1102#endif
1103 {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001104 current_x = 0;
Chris Allegretta88b09152001-05-17 11:35:43 +00001105 newnode->data = charalloc(strlen(tmp) + 1);
Chris Allegrettae3167732001-03-18 16:59:34 +00001106 strcpy(newnode->data, tmp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001107 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001108 *tmp = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001109
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001110 if (current->next == NULL)
Chris Allegrettae3167732001-03-18 16:59:34 +00001111 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001112 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001113
1114 totsize++;
1115 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001116 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001117 align(&current->data);
1118
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001119 /* The logic here is as follows:
1120 * -> If we are at the bottom of the buffer, we want to recenter
Chris Allegretta88520c92001-05-05 17:45:54 +00001121 * (read: rebuild) the screen and forcibly move the cursor.
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001122 * -> otherwise, we want simply to redraw the screen and update
1123 * where we think the cursor is.
1124 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001125 if (current_y == editwinrows - 1) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001126#ifndef NANO_SMALL
1127 if (ISSET(SMOOTHSCROLL))
1128 edit_update(current, NONE);
1129 else
1130#endif
1131 edit_update(current, CENTER);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001132 reset_cursor();
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001133 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001134 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001135 edit_refresh();
1136 update_cursor();
1137 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001138
1139 totlines++;
1140 set_modified();
1141
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001142 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001143 return 1;
1144}
1145
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001146#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001147int do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001148{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001149 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001150
Chris Allegretta6df90f52002-07-19 01:08:59 +00001151 /* Skip letters in this word first. */
1152 while (current->data[current_x] != '\0' &&
1153 isalnum((int)current->data[current_x]))
1154 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001155
Chris Allegretta6df90f52002-07-19 01:08:59 +00001156 for (; current != NULL; current = current->next) {
1157 while (current->data[current_x] != '\0' &&
1158 !isalnum((int)current->data[current_x]))
1159 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001160
Chris Allegretta6df90f52002-07-19 01:08:59 +00001161 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001162 break;
1163
Chris Allegretta6df90f52002-07-19 01:08:59 +00001164 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001165 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001166 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001167 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001168
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001169 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001170
David Lawrence Ramseybf3c93e2004-03-13 19:42:58 +00001171 /* Refresh the screen. If current has run off the bottom, this
1172 * call puts it at the center line. */
1173 edit_refresh();
1174
Chris Allegretta6232d662002-05-12 19:52:15 +00001175 return 0;
1176}
1177
Chris Allegretta6df90f52002-07-19 01:08:59 +00001178/* The same thing for backwards. */
1179int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001180{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001181 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001182
Chris Allegretta6df90f52002-07-19 01:08:59 +00001183 /* Skip letters in this word first. */
1184 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1185 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001186
Chris Allegretta6df90f52002-07-19 01:08:59 +00001187 for (; current != NULL; current = current->prev) {
1188 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1189 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001190
Chris Allegretta6df90f52002-07-19 01:08:59 +00001191 if (current_x >= 0)
1192 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001193
Chris Allegretta6df90f52002-07-19 01:08:59 +00001194 if (current->prev != NULL)
1195 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001196 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001197
Chris Allegretta6df90f52002-07-19 01:08:59 +00001198 if (current != NULL) {
1199 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1200 current_x--;
1201 } else {
1202 current = fileage;
1203 current_x = 0;
1204 }
1205
Chris Allegretta76e291b2001-10-14 19:05:10 +00001206 placewewant = xplustabs();
1207
David Lawrence Ramseyb6aa4282004-03-14 01:42:17 +00001208 /* Refresh the screen. If current has run off the top, this call
1209 * puts it at the center line. */
1210 edit_refresh();
1211
Chris Allegretta6232d662002-05-12 19:52:15 +00001212 return 0;
1213}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001214
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001215int do_mark(void)
1216{
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001217 TOGGLE(MARK_ISSET);
1218 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001219 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001220 mark_beginbuf = current;
1221 mark_beginx = current_x;
1222 } else {
1223 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001224 edit_refresh();
1225 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001226 return 1;
1227}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001228#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001229
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001230#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001231void wrap_reset(void)
1232{
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001233 same_line_wrap = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001234}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001235#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001236
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001237#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001238/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001239 * moved forward since the last typed character. Return value:
1240 * whether we wrapped. */
1241int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001242{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001243 size_t len = strlen(inptr->data); /* length of the line we wrap */
1244 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001245 int wrap_loc = -1; /* index of inptr->data where we wrap */
1246 int word_back = -1;
1247#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001248 const char *indentation = NULL;
1249 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001250 int indent_len = 0; /* strlen(indentation) */
1251#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001252 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001253 int after_break_len; /* strlen(after_break) */
1254 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001255 const char *wrap_line = NULL;
1256 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001257 int wrap_line_len = 0; /* strlen(wrap_line) */
1258 char *newline = NULL; /* the line we create */
1259 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001260
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001261/* There are three steps. First, we decide where to wrap. Then, we
1262 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001263
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001264/* Step 1, finding where to wrap. We are going to add a new-line
1265 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001266 * location of this replacement.
1267 *
1268 * Where should we break the line? We need the last "legal wrap point"
1269 * such that the last word before it ended at or before fill. If there
1270 * is no such point, we settle for the first legal wrap point.
1271 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001272 * A "legal wrap point" is a white-space character that is not followed by
1273 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001274 *
1275 * If there is no legal wrap point or we found the last character of the
1276 * line, we should return without wrapping.
1277 *
1278 * Note that the initial indentation does not count as a legal wrap
1279 * point if we are going to auto-indent!
1280 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001281 * Note that the code below could be optimised, by not calling strnlenpt()
1282 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001283
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001284#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001285 if (ISSET(AUTOINDENT))
1286 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001287#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001288 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001289 for (; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001290 /* record where the last word ended */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001291 if (!isblank(*wrap_line))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001292 word_back = i;
1293 /* if we have found a "legal wrap point" and the current word
1294 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001295 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001296 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001297 /* we record the latest "legal wrap point" */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001298 if (word_back != i && !isblank(wrap_line[1]))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001299 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001300 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001301 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001302 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001303
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001304/* Step 2, making the new wrap line. It will consist of indentation +
1305 * after_break + " " + wrap_line (although indentation and wrap_line are
1306 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001307
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001308 /* after_break is the text that will be moved to the next line. */
1309 after_break = inptr->data + wrap_loc + 1;
1310 after_break_len = len - wrap_loc - 1;
1311 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001312
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001313 /* new_line_len will later be increased by the lengths of indentation
1314 * and wrap_line. */
1315 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001316
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001317 /* We prepend the wrapped text to the next line, if the flag is set,
1318 * and there is a next line, and prepending would not make the line
1319 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001320 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001321 wrap_line = inptr->next->data;
1322 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001323
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001324 /* +1 for the space between after_break and wrap_line */
1325 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1326 wrapping = 1;
1327 new_line_len += (1 + wrap_line_len);
1328 }
1329 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001330
Chris Allegrettaff989832001-09-17 13:48:00 +00001331#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001332 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001333 /* Indentation comes from the next line if wrapping, else from
1334 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001335 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001336 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001337 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001338 /* The wrap_line text should not duplicate indentation.
1339 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001340 wrap_line += indent_len;
1341 else
1342 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001343 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001344#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001345
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001346 /* Now we allocate the new line and copy into it. */
1347 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1348 *newline = '\0';
1349
1350#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001351 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001352 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001353 newline[indent_len] = '\0';
1354 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001355#endif
1356 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001357 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001358 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001359 null_at(&inptr->data, wrap_loc + 1);
1360 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001361 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001362 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001363 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001364 * in a tab or a space, we don't add a space and decrement
1365 * totsize to account for that. */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001366 if (!isblank(newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001367 strcat(newline, " ");
1368 else
1369 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001370 strcat(newline, wrap_line);
1371 free(inptr->next->data);
1372 inptr->next->data = newline;
1373 } else {
1374 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001375
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001376 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001377 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001378#ifndef NANO_SMALL
1379 totsize += indent_len;
1380#endif
1381 totlines++;
1382 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001383 temp->prev = inptr;
1384 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001385 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001386 /* If temp->next is NULL, then temp is the last line of the
1387 * file, so we must set filebot. */
1388 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001389 temp->next->prev = temp;
1390 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001391 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001392 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001393
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001394/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1395 * other sundry things. */
1396
1397 /* later wraps of this line will be prepended to the next line. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001398 same_line_wrap = 1;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001399
1400 /* Each line knows its line number. We recalculate these if we
1401 * inserted a new line. */
1402 if (!wrapping)
1403 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001404
Chris Allegretta6df90f52002-07-19 01:08:59 +00001405 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001406 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001407 current = current->next;
1408 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001409#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001410 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001411#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001412 wrap_loc + 1;
1413 wrap_reset();
1414 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001415 }
1416
Chris Allegretta6df90f52002-07-19 01:08:59 +00001417#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001418 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001419 * If it was on the next line and we wrapped, we must move it
1420 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001421 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1422 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001423 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001424 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001425 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001426#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001427
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001428 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001429 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001430
1431 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001432}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001433#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001434
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001435#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001436/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001437 * return zero if the user cancels. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001438int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001439{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001440 char *save_search;
1441 char *save_replace;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001442 filestruct *current_save = current;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001443 size_t current_x_save = current_x;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001444 filestruct *edittop_save = edittop;
1445 /* Save where we are. */
1446 int i = 0;
1447 /* The return value. */
1448 int reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001449#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001450 int case_sens_set = ISSET(CASE_SENSITIVE);
1451 int mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001452
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001453 SET(CASE_SENSITIVE);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001454 /* Make sure the marking highlight is off during spell-check. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001455 UNSET(MARK_ISSET);
1456#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001457 /* Make sure spell-check goes forward only. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001458 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001459
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001460 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001461 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001462 save_search = last_search;
1463 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001464
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001465 /* Set search/replace strings to misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001466 last_search = mallocstrcpy(NULL, word);
1467 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001468
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001469 /* Start from the top of the file. */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001470 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001471 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001472
1473 search_last_line = FALSE;
1474
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001475 /* Find the first whole-word occurrence of word. */
1476 while (findnextstr(TRUE, TRUE, fileage, 0, word, FALSE) != 0)
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001477 if (is_whole_word(current_x, current->data, word)) {
1478 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001479
Chris Allegretta6df90f52002-07-19 01:08:59 +00001480 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001481
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001482 /* Allow the replace word to be corrected. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001483 i = statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001484#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001485 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001486#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001487 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001488
Chris Allegretta6df90f52002-07-19 01:08:59 +00001489 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001490
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001491 if (i != -1 && strcmp(word, answer)) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001492 search_last_line = FALSE;
1493 current_x--;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001494 do_replace_loop(word, current_save, &current_x_save, TRUE);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001495 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001496
1497 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001498 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001499
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001500 /* Restore the search/replace strings. */
1501 free(last_search);
1502 last_search = save_search;
1503 free(last_replace);
1504 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001505
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001506 /* Restore where we were. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001507 current = current_save;
1508 current_x = current_x_save;
1509 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001510
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001511 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001512 if (reverse_search_set)
1513 SET(REVERSE_SEARCH);
1514
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001515#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001516 if (!case_sens_set)
1517 UNSET(CASE_SENSITIVE);
1518
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001519 /* Restore marking highlight. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001520 if (mark_set)
1521 SET(MARK_ISSET);
1522#endif
1523
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001524 return i != -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001525}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001526
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001527/* Integrated spell checking using 'spell' program. Return value: NULL
1528 * for normal termination, otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001529char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001530{
Chris Allegretta271e9722000-11-10 18:15:43 +00001531 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001532 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001533 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001534 pid_t pid_spell, pid_sort, pid_uniq;
1535 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001536
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001537 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001538 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1539 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001540
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001541 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001542
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001543 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001544 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001545
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001546 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001547
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001548 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001549
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001550 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001551 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1552 goto close_pipes_and_exit;
1553
1554 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1555 goto close_pipes_and_exit;
1556
Chris Allegretta271e9722000-11-10 18:15:43 +00001557 close(tempfile_fd);
1558
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001559 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001560 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1561 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001562
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001563 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001564
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001565 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001566 execlp("spell", "spell", NULL);
1567
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001568 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001569 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001570 }
1571
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001572 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001573 close(spell_fd[1]);
1574
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001575 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001576 if ((pid_sort = fork()) == 0) {
1577
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001578 /* Child continues (i.e, future spell process). Replace the
1579 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001580 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1581 goto close_pipes_and_exit;
1582
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001583 close(spell_fd[0]);
1584
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001585 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001586 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1587 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001588
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001589 close(sort_fd[1]);
1590
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001591 /* Start sort program. Use -f to remove mixed case without
1592 * having to have ANOTHER pipe for tr. If this isn't portable,
1593 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001594 execlp("sort", "sort", "-f", NULL);
1595
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001596 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001597 exit(1);
1598 }
1599
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001600 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001601 close(sort_fd[1]);
1602
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001603 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001604 if ((pid_uniq = fork()) == 0) {
1605
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001606 /* Child continues (i.e, future uniq process). Replace the
1607 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001608 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1609 goto close_pipes_and_exit;
1610
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001611 close(sort_fd[0]);
1612
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001613 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001614 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1615 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001616
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001617 close(uniq_fd[1]);
1618
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001619 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001620 execlp("uniq", "uniq", NULL);
1621
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001622 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001623 exit(1);
1624 }
1625
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001626 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001627 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001628
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001629 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001630 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1631 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001632 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001633 }
1634
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001635 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001636 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1637 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001638 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001639 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001640
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001641 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001642 read_buff_read = 0;
1643 read_buff_size = pipe_buff_size + 1;
1644 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001645
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001646 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001647 read_buff_read += bytesread;
1648 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001649 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001650 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001651
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001652 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001653
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001654 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001655 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001656
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001657 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001658 read_buff_word = read_buff_ptr = read_buff;
1659
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001660 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001661
1662 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001663 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001664 if (read_buff_word != read_buff_ptr) {
1665 if (!do_int_spell_fix(read_buff_word)) {
1666 read_buff_word = read_buff_ptr;
1667 break;
1668 }
1669 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001670 read_buff_word = read_buff_ptr + 1;
1671 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001672 read_buff_ptr++;
1673 }
1674
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001675 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001676 if (read_buff_word != read_buff_ptr)
1677 do_int_spell_fix(read_buff_word);
1678
Chris Allegretta271e9722000-11-10 18:15:43 +00001679 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001680 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001681 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001682
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001683 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001684 waitpid(pid_spell, &spell_status, 0);
1685 waitpid(pid_sort, &sort_status, 0);
1686 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001687
Chris Allegretta334a9402002-12-16 04:25:53 +00001688 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1689 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001690
Chris Allegretta334a9402002-12-16 04:25:53 +00001691 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1692 return _("Error invoking \"sort -f\"");
1693
1694 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1695 return _("Error invoking \"uniq\"");
1696
1697 /* Otherwise... */
1698 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001699
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001700 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001701
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001702 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001703 close(tempfile_fd);
1704 close(spell_fd[0]);
1705 close(spell_fd[1]);
1706 close(sort_fd[0]);
1707 close(sort_fd[1]);
1708 close(uniq_fd[0]);
1709 close(uniq_fd[1]);
1710 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001711}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001712
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001713/* External spell checking. Return value: NULL for normal termination,
1714 * otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001715char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001716{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001717 int alt_spell_status, lineno_cur = current->lineno;
1718 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001719 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001720 char *ptr;
1721 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001722 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001723#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001724 int mark_set = ISSET(MARK_ISSET);
1725 int mbb_lineno_cur = 0;
1726 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001727 * the alternate spell command. The line that mark_beginbuf
1728 * points to will be freed, so we save the line number and
1729 * restore afterwards. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001730
1731 if (mark_set) {
1732 mbb_lineno_cur = mark_beginbuf->lineno;
1733 UNSET(MARK_ISSET);
1734 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001735#endif
1736
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001737 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001738
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001739 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001740 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001741 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001742
Chris Allegrettae434b452001-01-27 19:25:00 +00001743 spellargs[0] = strtok(alt_speller, " ");
1744 while ((ptr = strtok(NULL, " ")) != NULL) {
1745 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001746 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001747 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001748 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001749 spellargs[arglen - 1] = NULL;
1750 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001751 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001752
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001753 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001754 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001755 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00001756 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001757
1758 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001759 exit(1);
1760 }
1761
1762 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001763 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001764 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001765
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001766 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001767 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001768
Chris Allegretta334a9402002-12-16 04:25:53 +00001769 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1770 char *altspell_error = NULL;
1771 char *invoke_error = _("Could not invoke \"%s\"");
1772 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1773
1774 altspell_error = charalloc(msglen);
1775 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1776 return altspell_error;
1777 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001778
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001779 refresh();
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001780#ifndef NANO_SMALL
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001781 if (!mark_set) {
1782 /* Only reload the temp file if it isn't a marked selection. */
1783#endif
1784 free_filestruct(fileage);
1785 global_init(1);
1786 open_file(tempfile_name, 0, 1);
1787#ifndef NANO_SMALL
1788 }
1789
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001790 if (mark_set) {
1791 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1792 mark_beginbuf = current;
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001793 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001794 mark_beginx = current_x;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001795 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001796 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001797#endif
1798
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001799 /* Go back to the old position, mark the file as modified, and make
1800 * sure that the titlebar is refreshed. */
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001801 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001802 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001803 clearok(topwin, FALSE);
1804 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001805
Chris Allegretta334a9402002-12-16 04:25:53 +00001806 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001807}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001808
1809int do_spell(void)
1810{
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001811 int i;
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001812 char *temp, *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001813
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001814 if ((temp = safe_tempnam(0, "nano.")) == NULL) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001815 statusbar(_("Could not create a temporary filename: %s"),
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001816 strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001817 return 0;
1818 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001819
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001820#ifndef NANO_SMALL
1821 if (ISSET(MARK_ISSET))
1822 i = write_marked(temp, 1, 0, 0);
1823 else
1824#endif
1825 i = write_file(temp, 1, 0, 0);
1826
1827 if (i == -1) {
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001828 statusbar(_("Spell checking failed: unable to write temp file!"));
Chris Allegrettabef12972002-03-06 03:30:40 +00001829 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001830 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001831 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001832
Chris Allegrettae1f14522001-09-19 03:19:43 +00001833#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001834 /* Update the current open_files entry before spell-checking, in
1835 * case any problems occur. */
Chris Allegretta48b06702002-02-22 04:30:50 +00001836 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001837#endif
1838
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001839 if (alt_speller != NULL)
Chris Allegretta334a9402002-12-16 04:25:53 +00001840 spell_msg = do_alt_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001841 else
Chris Allegretta334a9402002-12-16 04:25:53 +00001842 spell_msg = do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001843 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001844 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001845
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001846 if (spell_msg != NULL) {
Chris Allegretta334a9402002-12-16 04:25:53 +00001847 statusbar(_("Spell checking failed: %s"), spell_msg);
1848 return 0;
1849 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001850
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001851 statusbar(_("Finished checking spelling"));
1852 return 1;
Chris Allegretta67105eb2000-07-03 03:18:32 +00001853}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001854#endif /* !DISABLE_SPELLER */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001855
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001856#if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001857/* The "indentation" of a line is the white-space between the quote part
1858 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001859size_t indent_length(const char *line)
1860{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001861 size_t len = 0;
1862
1863 assert(line != NULL);
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001864 while (isblank(*line)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001865 line++;
1866 len++;
1867 }
1868 return len;
1869}
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001870#endif /* !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001871
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001872#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001873/* justify_format() replaces Tab by Space and multiple spaces by 1
1874 * (except it maintains 2 after a . ! or ?). Note the terminating \0
Chris Allegretta6df90f52002-07-19 01:08:59 +00001875 * counts as a space.
1876 *
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001877 * justify_format() might make line->data shorter, and change the actual
1878 * pointer with null_at().
Chris Allegretta6df90f52002-07-19 01:08:59 +00001879 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001880 * justify_format() will not look at the first skip characters of line.
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001881 * skip should be at most strlen(line->data). The character at
1882 * line[skip + 1] must not be whitespace. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001883void justify_format(filestruct *line, size_t skip)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001884{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001885 const char *punct = ".?!";
1886 const char *brackets = "'\")}]>";
Chris Allegretta6df90f52002-07-19 01:08:59 +00001887 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001888
Chris Allegretta6df90f52002-07-19 01:08:59 +00001889 /* These four asserts are assumptions about the input data. */
1890 assert(line != NULL);
1891 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001892 assert(skip < strlen(line->data));
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001893 assert(!isblank(line->data[skip]));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001894
Chris Allegretta6df90f52002-07-19 01:08:59 +00001895 back = line->data + skip;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001896 for (front = back; ; front++) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001897 int remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001898 /* Do we want to remove this space? */
1899
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001900 if (*front == '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001901 *front = ' ';
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001902
David Lawrence Ramsey021960d2004-05-13 23:19:01 +00001903 /* These tests are safe since line->data + skip is not a
1904 * space. */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001905 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001906 const char *bob = front - 2;
1907
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001908 remove_space = TRUE;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001909 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001910 if (strchr(punct, *bob) != NULL) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001911 remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001912 break;
1913 }
1914 if (strchr(brackets, *bob) == NULL)
1915 break;
1916 }
1917 }
1918
1919 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001920 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001921 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001922#ifndef NANO_SMALL
1923 if (mark_beginbuf == line && back - line->data < mark_beginx)
1924 mark_beginx--;
1925#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001926 if (*front == '\0')
1927 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00001928 } else {
1929 *back = *front;
1930 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001931 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001932 if (*front == '\0')
1933 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001934 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001935
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001936 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00001937 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00001938
Chris Allegretta6df90f52002-07-19 01:08:59 +00001939 /* Now back is the new end of line->data. */
1940 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00001941 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001942 null_at(&line->data, back - line->data);
1943#ifndef NANO_SMALL
1944 if (mark_beginbuf == line && back - line->data < mark_beginx)
1945 mark_beginx = back - line->data;
1946#endif
1947 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001948}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001949
1950/* The "quote part" of a line is the largest initial substring matching
1951 * the quote string. This function returns the length of the quote part
1952 * of the given line.
1953 *
1954 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1955 * quotestr. */
1956#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001957size_t quote_length(const char *line, const regex_t *qreg)
1958{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001959 regmatch_t matches;
1960 int rc = regexec(qreg, line, 1, &matches, 0);
1961
1962 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
1963 return 0;
1964 /* matches.rm_so should be 0, since the quote string should start with
1965 * the caret ^. */
1966 return matches.rm_eo;
1967}
1968#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001969size_t quote_length(const char *line)
1970{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001971 size_t qdepth = 0;
1972 size_t qlen = strlen(quotestr);
1973
1974 /* Compute quote depth level */
1975 while (!strcmp(line + qdepth, quotestr))
1976 qdepth += qlen;
1977 return qdepth;
1978}
1979#endif /* !HAVE_REGEX_H */
1980
Chris Allegretta6df90f52002-07-19 01:08:59 +00001981/* a_line and b_line are lines of text. The quotation part of a_line is
1982 * the first a_quote characters. Check that the quotation part of
1983 * b_line is the same. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00001984int quotes_match(const char *a_line, size_t a_quote, IFREG(const char
1985 *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001986{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001987 /* Here is the assumption about a_quote: */
1988 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00001989 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00001990 !strncmp(a_line, b_line, a_quote);
1991}
1992
1993/* We assume a_line and b_line have no quote part. Then, we return whether
1994 * b_line could follow a_line in a paragraph. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00001995size_t indents_match(const char *a_line, size_t a_indent, const char
1996 *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001997{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001998 assert(a_indent == indent_length(a_line));
1999 assert(b_indent == indent_length(b_line));
2000
2001 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2002}
2003
2004/* Put the next par_len lines, starting with first_line, in the cut
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002005 * buffer, not allowing them to be concatenated. We assume there are
2006 * enough lines after first_line. We leave copies of the lines in
2007 * place, too. We return the new copy of first_line. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002008filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t
2009 quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002010{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002011 /* We put the original lines, not copies, into the cutbuffer, just
2012 * out of a misguided sense of consistency, so if you uncut, you get
2013 * the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002014 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002015
2016 set_modified();
2017 cutbuffer = NULL;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002018 for (; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002019 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002020
Chris Allegretta908f7702003-01-15 11:18:58 +00002021 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002022 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002023 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002024 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002025 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002026 edittop = bob;
2027#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002028 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002029 mark_beginbuf = bob;
2030#endif
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002031 justify_format(bob, quote_len + indent_length(bob->data + quote_len));
Chris Allegretta6df90f52002-07-19 01:08:59 +00002032
Chris Allegretta908f7702003-01-15 11:18:58 +00002033 assert(alice != NULL && bob != NULL);
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002034 add_to_cutbuffer(alice, FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002035 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002036 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002037 }
2038 return first_line;
2039}
2040
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002041/* Is it possible to break line at or before goal? */
2042int breakable(const char *line, int goal)
2043{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002044 for (; *line != '\0' && goal >= 0; line++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002045 if (isblank(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002046 return TRUE;
2047
2048 if (is_cntrl_char(*line) != 0)
2049 goal -= 2;
2050 else
2051 goal -= 1;
2052 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002053 /* If goal is not negative, the whole line (one word) was short
2054 * enough. */
2055 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002056}
2057
Chris Allegretta6df90f52002-07-19 01:08:59 +00002058/* We are trying to break a chunk off line. We find the last space such
2059 * that the display length to there is at most goal + 1. If there is
2060 * no such space, and force is not 0, then we find the first space.
2061 * Anyway, we then take the last space in that group of spaces. The
2062 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002063int break_line(const char *line, int goal, int force)
2064{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002065 /* Note that we use int instead of size_t, since goal is at most COLS,
2066 * the screen width, which will always be reasonably small. */
2067 int space_loc = -1;
2068 /* Current tentative return value. Index of the last space we
2069 * found with short enough display width. */
2070 int cur_loc = 0;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002071 /* Current index in line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002072
2073 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002074 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002075 if (*line == ' ')
2076 space_loc = cur_loc;
2077 assert(*line != '\t');
2078
Chris Allegrettacf287c82002-07-20 13:57:41 +00002079 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002080 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002081 else
2082 goal--;
2083 }
2084 if (goal >= 0)
2085 /* In fact, the whole line displays shorter than goal. */
2086 return cur_loc;
2087 if (space_loc == -1) {
2088 /* No space found short enough. */
2089 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002090 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002091 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002092 return cur_loc;
2093 return -1;
2094 }
2095 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002096 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002097 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2098 *(line - cur_loc + space_loc + 1) == '\0')
2099 space_loc++;
2100 return space_loc;
2101}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002102
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002103/* Search a paragraph. If search_type is 0, search for the beginning of
2104 * the current paragraph or, if we're at the end of it, the beginning of
2105 * the next paragraph. If search_type is 1, search for the beginning of
2106 * the current paragraph or, if we're already there, the beginning of
2107 * the previous paragraph. If search_type is 2, search for the end of
2108 * the current paragraph or, if we're already there, the end of the next
2109 * paragraph. Afterwards, save the quote length, paragraph length, and
2110 * indentation length in *quote, *par, and *indent if they aren't NULL,
2111 * and refresh the screen if do_refresh is nonzero. Return 0 if we
2112 * found a paragraph, or 1 if there was an error or we didn't find a
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002113 * paragraph.
2114 *
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002115 * To explain the searching algorithm, I first need to define some
Chris Allegretta6df90f52002-07-19 01:08:59 +00002116 * phrases about paragraphs and quotation:
2117 * A line of text consists of a "quote part", followed by an
2118 * "indentation part", followed by text. The functions quote_length()
2119 * and indent_length() calculate these parts.
2120 *
2121 * A line is "part of a paragraph" if it has a part not in the quote
2122 * part or the indentation.
2123 *
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002124 * A line is "the beginning of a paragraph" if it is part of a
2125 * paragraph and
Chris Allegretta6df90f52002-07-19 01:08:59 +00002126 * 1) it is the top line of the file, or
2127 * 2) the line above it is not part of a paragraph, or
2128 * 3) the line above it does not have precisely the same quote
2129 * part, or
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002130 * 4) the indentation of this line is not an initial substring of
2131 * the indentation of the previous line, or
Chris Allegretta6df90f52002-07-19 01:08:59 +00002132 * 5) this line has no quote part and some indentation, and
2133 * AUTOINDENT is not set.
2134 * The reason for number 5) is that if AUTOINDENT is not set, then an
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002135 * indented line is expected to start a paragraph, like in books.
2136 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2137 * turned on.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002138 *
2139 * A contiguous set of lines is a "paragraph" if each line is part of
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002140 * a paragraph and only the first line is the beginning of a
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002141 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002142int do_para_search(int search_type, size_t *quote, size_t *par, size_t
2143 *indent, int do_refresh)
2144{
2145 size_t quote_len;
2146 /* Length of the initial quotation of the paragraph we
2147 * search. */
2148 size_t par_len;
2149 /* Number of lines in that paragraph. */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002150
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002151 /* We save this global variable to see if we're where we started
2152 * when searching for the beginning of the paragraph. */
2153 filestruct *current_save = current;
2154
2155 size_t indent_len; /* Generic indentation length. */
2156 filestruct *line; /* Generic line of text. */
2157
2158 static int do_restart = 1;
2159 /* Whether we're restarting when searching for the beginning
2160 * line of the paragraph. */
2161
2162#ifdef HAVE_REGEX_H
2163 regex_t qreg; /* qreg is the compiled quotation regexp. We no
2164 * longer care about quotestr. */
2165 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2166
2167 if (rc != 0) {
2168 size_t size = regerror(rc, &qreg, NULL, 0);
2169 char *strerror = charalloc(size);
2170
2171 regerror(rc, &qreg, strerror, size);
2172 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2173 free(strerror);
2174 return 1;
2175 }
2176#endif
2177
2178 /* Here is an assumption that is always true anyway. */
2179 assert(current != NULL);
2180
2181 current_x = 0;
2182
2183 restart_para_search:
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002184 /* Here we find the first line of the paragraph to search. If the
2185 * current line is in a paragraph, then we move back to the first
2186 * line. Otherwise, we move to the first line that is in a
2187 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002188 quote_len = quote_length(IFREG(current->data, &qreg));
2189 indent_len = indent_length(current->data + quote_len);
2190
2191 if (current->data[quote_len + indent_len] != '\0') {
2192 /* This line is part of a paragraph. So we must search back to
2193 * the first line of this paragraph. First we check items 1)
2194 * and 3) above. */
2195 while (current->prev != NULL && quotes_match(current->data,
2196 quote_len, IFREG(current->prev->data, &qreg))) {
2197 size_t temp_id_len =
2198 indent_length(current->prev->data + quote_len);
2199 /* The indentation length of the previous line. */
2200
2201 /* Is this line the beginning of a paragraph, according to
2202 * items 2), 5), or 4) above? If so, stop. */
2203 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002204 (quote_len == 0 && indent_len > 0
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002205#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002206 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002207#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002208 ) || !indents_match(current->prev->data + quote_len,
2209 temp_id_len, current->data + quote_len, indent_len))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002210 break;
2211 indent_len = temp_id_len;
2212 current = current->prev;
2213 current_y--;
2214 }
2215 } else if (search_type == 1) {
2216 /* This line is not part of a paragraph. Move up until we get
2217 * to a non "blank" line, and then move down once. */
2218 do {
2219 /* There is no previous paragraph, so nothing to move to. */
2220 if (current->prev == NULL) {
2221 placewewant = 0;
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002222 if (do_refresh)
2223 edit_refresh();
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002224#ifdef HAVE_REGEX_H
2225 if (!do_restart)
2226 regfree(&qreg);
2227#endif
2228 return 1;
2229 }
2230 current = current->prev;
2231 current_y--;
2232 quote_len = quote_length(IFREG(current->data, &qreg));
2233 indent_len = indent_length(current->data + quote_len);
2234 } while (current->data[quote_len + indent_len] == '\0');
2235 current = current->next;
2236 } else {
2237 /* This line is not part of a paragraph. Move down until we get
2238 * to a non "blank" line. */
2239 do {
2240 /* There is no next paragraph, so nothing to move to. */
2241 if (current->next == NULL) {
2242 placewewant = 0;
2243 if (do_refresh)
2244 edit_refresh();
2245#ifdef HAVE_REGEX_H
2246 regfree(&qreg);
2247#endif
2248 return 1;
2249 }
2250 current = current->next;
2251 current_y++;
2252 quote_len = quote_length(IFREG(current->data, &qreg));
2253 indent_len = indent_length(current->data + quote_len);
2254 } while (current->data[quote_len + indent_len] == '\0');
2255 }
2256
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002257 /* Now current is the first line of the paragraph, and quote_len is
2258 * the quotation length of that line. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002259
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002260 /* Next step, compute par_len, the number of lines in this
2261 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002262 line = current;
2263 par_len = 1;
2264 indent_len = indent_length(line->data + quote_len);
2265
2266 while (line->next != NULL && quotes_match(current->data, quote_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002267 IFREG(line->next->data, &qreg))) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002268 size_t temp_id_len = indent_length(line->next->data + quote_len);
2269
2270 if (!indents_match(line->data + quote_len, indent_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002271 line->next->data + quote_len, temp_id_len) ||
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002272 line->next->data[quote_len + temp_id_len] == '\0' ||
2273 (quote_len == 0 && temp_id_len > 0
2274#ifndef NANO_SMALL
2275 && !ISSET(AUTOINDENT)
2276#endif
2277 ))
2278 break;
2279 indent_len = temp_id_len;
2280 line = line->next;
2281 par_len++;
2282 }
2283
2284 if (search_type == 1) {
2285 /* We're on the same line we started on. Move up until we get
2286 * to a non-"blank" line, restart the search from there until we
2287 * find a line that's part of a paragraph, and search once more
2288 * so that we end up at the beginning of that paragraph. */
2289 if (current != fileage && current == current_save && do_restart) {
2290 while (current->prev != NULL) {
2291 size_t i, j = 0;
2292 current = current->prev;
2293 current_y--;
2294 /* Skip over lines consisting only of spacing
2295 * characters, as searching for the end of the paragraph
2296 * does. */
2297 for (i = 0; current->data[i] != '\0'; i++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002298 if (isblank(current->data[i]))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002299 j++;
2300 else {
2301 i = 0;
2302 j = 1;
2303 break;
2304 }
2305 }
2306 if (i != j && strlen(current->data) >=
2307 (quote_len + indent_len) &&
2308 current->data[quote_len + indent_len] != '\0') {
2309 do_restart = 0;
2310 break;
2311 }
2312 }
2313 goto restart_para_search;
2314 } else
2315 do_restart = 1;
2316 }
2317
2318#ifdef HAVE_REGEX_H
2319 /* We no longer need to check quotation. */
2320 regfree(&qreg);
2321#endif
2322
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002323 /* Now par_len is the number of lines in this paragraph. We should
2324 * never call quotes_match() or quote_length() again. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002325
2326 /* If we're searching for the end of the paragraph, move down the
2327 * number of lines in the paragraph. */
2328 if (search_type == 2) {
2329 for (; par_len > 0; current_y++, par_len--)
2330 current = current->next;
2331 }
2332
2333 /* Refresh the screen if needed. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002334 if (do_refresh)
2335 edit_refresh();
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002336
2337 /* Save the values of quote_len, par_len, and indent_len if
2338 * needed. */
2339 if (quote != NULL)
2340 *quote = quote_len;
2341 if (par != NULL)
2342 *par = par_len;
2343 if (indent != NULL)
2344 *indent = indent_len;
2345
2346 return 0;
2347}
2348
2349int do_para_begin(void)
2350{
2351 return do_para_search(1, NULL, NULL, NULL, TRUE);
2352}
2353
2354int do_para_end(void)
2355{
2356 return do_para_search(2, NULL, NULL, NULL, TRUE);
2357}
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002358
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002359/* If full_justify is TRUE, justify the entire file. Otherwise, justify
2360 * the current paragraph. */
2361int do_justify(int full_justify)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002362{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002363 size_t quote_len;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002364 /* Length of the initial quotation of the paragraph we
2365 * justify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002366 size_t par_len;
2367 /* Number of lines in that paragraph. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002368 filestruct *first_par_line = NULL;
2369 /* Will be the first line of the resulting justified paragraph.
2370 * For restoring after uncut. */
David Lawrence Ramsey36e363f2004-05-17 20:38:00 +00002371 filestruct *last_par_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002372 /* Will be the last line of the result, also for uncut. */
2373 filestruct *cutbuffer_save = cutbuffer;
2374 /* When the paragraph gets modified, all lines from the changed
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002375 * one down are stored in the cutbuffer. We back up the
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002376 * original to restore it later. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002377
2378 /* We save these global variables to be restored if the user
2379 * unjustifies. Note we don't need to save totlines. */
2380 int current_x_save = current_x;
2381 int current_y_save = current_y;
2382 filestruct *current_save = current;
2383 int flags_save = flags;
2384 long totsize_save = totsize;
2385 filestruct *edittop_save = edittop;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002386#ifndef NANO_SMALL
2387 filestruct *mark_beginbuf_save = mark_beginbuf;
2388 int mark_beginx_save = mark_beginx;
2389#endif
2390
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002391 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002392 size_t i; /* Generic loop variable. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002393
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002394 /* If we're justifying the entire file, start at the beginning. */
2395 if (full_justify)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002396 current = fileage;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002397
2398 last_par_line = current;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002399
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002400 while (TRUE) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002401
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002402 /* First, search for the beginning of the current paragraph or,
2403 * if we're at the end of it, the beginning of the next
2404 * paragraph. Save the quote length, paragraph length, and
2405 * indentation length and don't refresh the screen yet (since
2406 * we'll do that after we justify). If the search failed and
2407 * we're justifying the whole file, move the last line of the
2408 * text we're justifying to just before the magicline, which is
2409 * where it'll be anyway if we've searched the entire file, and
2410 * break out of the loop; otherwise, refresh the screen and get
2411 * out. */
2412 if (do_para_search(0, &quote_len, &par_len, &indent_len, FALSE) != 0) {
2413 if (full_justify) {
2414 /* This should be safe in the event of filebot->prev's
2415 * being NULL, since only last_par_line->next is used if
2416 * we eventually unjustify. */
2417 last_par_line = filebot->prev;
2418 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002419 } else {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002420 edit_refresh();
2421 return 0;
2422 }
2423 }
2424
2425 /* Next step, we loop through the lines of this paragraph,
2426 * justifying each one individually. */
2427 for (; par_len > 0; current_y++, par_len--) {
2428 size_t line_len;
2429 size_t display_len;
2430 /* The width of current in screen columns. */
2431 int break_pos;
2432 /* Where we will break the line. */
2433
2434 indent_len = indent_length(current->data + quote_len) +
2435 quote_len;
2436
2437 /* justify_format() removes excess spaces from the line, and
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002438 * changes tabs to spaces. After calling it, we call
2439 * backup_lines(), which copies the original paragraph to
2440 * the cutbuffer for unjustification and then calls
2441 * justify_format() on the remaining lines. */
2442 justify_format(current, indent_len);
2443 if (first_par_line == NULL)
2444 first_par_line = backup_lines(current, full_justify ?
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002445 filebot->lineno - current->lineno : par_len, quote_len);
2446
2447 line_len = strlen(current->data);
2448 display_len = strlenpt(current->data);
2449
2450 if (display_len > fill) {
2451 /* The line is too long. Try to wrap it to the next. */
2452 break_pos = break_line(current->data + indent_len,
2453 fill - strnlenpt(current->data, indent_len), TRUE);
2454 if (break_pos == -1 || break_pos + indent_len == line_len)
2455 /* We can't break the line, or don't need to, so
2456 * just go on to the next. */
2457 goto continue_loc;
2458 break_pos += indent_len;
2459 assert(break_pos < line_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002460 if (par_len == 1) {
2461 /* There is no next line in this paragraph. We make
2462 * a new line and copy text after break_pos into
2463 * it. */
2464 splice_node(current, make_new_node(current), current->next);
2465 /* In a non-quoted paragraph, we copy the indent
2466 * only if AUTOINDENT is turned on. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002467 if (quote_len == 0
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002468#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002469 && !ISSET(AUTOINDENT)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002470#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002471 )
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002472 indent_len = 0;
2473 current->next->data = charalloc(indent_len + line_len -
2474 break_pos);
2475 strncpy(current->next->data, current->data, indent_len);
2476 strcpy(current->next->data + indent_len,
2477 current->data + break_pos + 1);
2478 assert(strlen(current->next->data) ==
2479 indent_len + line_len - break_pos - 1);
2480 totlines++;
2481 totsize += indent_len;
2482 par_len++;
2483 } else {
2484 size_t next_line_len = strlen(current->next->data);
2485
2486 indent_len = quote_len +
2487 indent_length(current->next->data + quote_len);
2488 current->next->data = charealloc(current->next->data,
2489 next_line_len + line_len - break_pos + 1);
2490
2491 charmove(current->next->data + indent_len + line_len -
2492 break_pos, current->next->data + indent_len,
2493 next_line_len - indent_len + 1);
2494 strcpy(current->next->data + indent_len,
2495 current->data + break_pos + 1);
2496 current->next->data[indent_len + line_len - break_pos - 1]
2497 = ' ';
2498#ifndef NANO_SMALL
2499 if (mark_beginbuf == current->next) {
2500 if (mark_beginx < indent_len)
2501 mark_beginx = indent_len;
2502 mark_beginx += line_len - break_pos;
2503 }
2504#endif
2505 }
2506#ifndef NANO_SMALL
2507 if (mark_beginbuf == current && mark_beginx > break_pos) {
2508 mark_beginbuf = current->next;
2509 mark_beginx -= break_pos + 1 - indent_len;
2510 }
2511#endif
2512 null_at(&current->data, break_pos);
2513 current = current->next;
2514 } else if (display_len < fill && par_len > 1) {
2515 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002516
2517 indent_len = quote_len +
2518 indent_length(current->next->data + quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002519 /* If we can't pull a word from the next line up to this
2520 * one, just go on. */
2521 if (!breakable(current->next->data + indent_len,
2522 fill - display_len - 1))
2523 goto continue_loc;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002524
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002525 break_pos = break_line(current->next->data + indent_len,
2526 fill - display_len - 1, FALSE);
2527 assert(break_pos != -1);
2528
2529 current->data = charealloc(current->data,
2530 line_len + break_pos + 2);
2531 current->data[line_len] = ' ';
2532 strncpy(current->data + line_len + 1,
2533 current->next->data + indent_len, break_pos);
2534 current->data[line_len + break_pos + 1] = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002535#ifndef NANO_SMALL
2536 if (mark_beginbuf == current->next) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002537 if (mark_beginx < indent_len + break_pos) {
2538 mark_beginbuf = current;
2539 if (mark_beginx <= indent_len)
2540 mark_beginx = line_len + 1;
2541 else
2542 mark_beginx = line_len + 1 + mark_beginx - indent_len;
2543 } else
2544 mark_beginx -= break_pos + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002545 }
2546#endif
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002547 next_line_len = strlen(current->next->data);
2548 if (indent_len + break_pos == next_line_len) {
2549 filestruct *line = current->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002550
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002551 /* Don't destroy edittop! */
2552 if (line == edittop)
2553 edittop = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002554
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002555 unlink_node(line);
2556 delete_node(line);
2557 totlines--;
2558 totsize -= indent_len;
2559 current_y--;
2560 } else {
2561 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002562 current->next->data + indent_len + break_pos + 1,
2563 next_line_len - break_pos - indent_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002564 null_at(&current->next->data, next_line_len - break_pos);
2565 current = current->next;
2566 }
2567 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002568 continue_loc:
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002569 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002570 current = current->next;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002571
2572 /* If the line we were on before still exists, and it was
2573 * not the last line of the paragraph, add a space to the
2574 * end of it to replace the one removed by
2575 * justify_format(). */
2576 if (current->prev != NULL && par_len > 1) {
2577 size_t prev_line_len = strlen(current->prev->data);
2578 current->prev->data = charealloc(current->prev->data,
2579 prev_line_len + 2);
2580 current->prev->data[prev_line_len] = ' ';
2581 current->prev->data[prev_line_len + 1] = '\0';
2582 totsize++;
2583 }
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002584 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002585
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002586 /* We've just justified a paragraph. If we're not justifying the
2587 * entire file, break out of the loop. Otherwise, continue the
2588 * loop so that we justify all the paragraphs in the file. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002589 if (!full_justify)
2590 break;
2591
2592 } /* while (TRUE) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002593
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002594 /* We are now done justifying the paragraph or the file, so clean
2595 * up. totlines, totsize, and current_y have been maintained above.
2596 * Set last_par_line to the new end of the paragraph, update
2597 * fileage, and set current_x. Also, edit_refresh() needs the line
2598 * numbers to be right, so renumber(). */
2599 last_par_line = current->prev;
2600 if (first_par_line->prev == NULL)
2601 fileage = first_par_line;
2602 renumber(first_par_line);
2603
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002604 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002605
Chris Allegretta9149e612000-11-27 00:23:41 +00002606 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002607 /* Display the shortcut list with UnJustify. */
Chris Allegretta07798352000-11-27 22:58:23 +00002608 shortcut_init(1);
2609 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002610 reset_cursor();
2611
Chris Allegretta6df90f52002-07-19 01:08:59 +00002612 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002613 * keystroke and return. */
Chris Allegretta5f071802001-05-06 02:34:31 +00002614
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002615 {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002616 int meta_key;
2617 i = get_kbinput(edit, &meta_key);
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002618#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002619 /* If it was a mouse click, parse it with do_mouse() and it
2620 * might become the unjustify key. Else give it back to the
2621 * input stream. */
2622 if (i == KEY_MOUSE)
2623 do_mouse();
2624 else
2625 ungetch(i);
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002626 i = get_kbinput(edit, &meta_key);
Chris Allegretta5f071802001-05-06 02:34:31 +00002627#endif
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002628 }
Chris Allegretta5f071802001-05-06 02:34:31 +00002629
David Lawrence Ramseyc91696e2004-01-29 04:16:23 +00002630 if (i != NANO_UNJUSTIFY_KEY && i != NANO_UNJUSTIFY_FKEY) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002631 ungetch(i);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002632 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002633 } else {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002634 /* Else restore the justify we just did (ungrateful user!). */
2635 filestruct *cutbottom = get_cutbottom();
2636
Chris Allegretta6df90f52002-07-19 01:08:59 +00002637 current = current_save;
2638 current_x = current_x_save;
2639 current_y = current_y_save;
2640 edittop = edittop_save;
Chris Allegrettad022eac2000-11-27 02:50:49 +00002641
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002642 /* Splice the cutbuffer back into the file. */
2643 cutbottom->next = last_par_line->next;
2644 cutbottom->next->prev = cutbottom;
2645 /* The line numbers after the end of the paragraph have been
2646 * changed, so we change them back. */
2647 renumber(cutbottom->next);
2648 if (first_par_line->prev != NULL) {
2649 cutbuffer->prev = first_par_line->prev;
2650 cutbuffer->prev->next = cutbuffer;
2651 } else
2652 fileage = cutbuffer;
2653 cutbuffer = NULL;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002654
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002655 last_par_line->next = NULL;
2656 free_filestruct(first_par_line);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002657
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002658 /* Restore global variables from before the justify. */
2659 totsize = totsize_save;
2660 totlines = filebot->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002661#ifndef NANO_SMALL
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002662 mark_beginbuf = mark_beginbuf_save;
2663 mark_beginx = mark_beginx_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002664#endif
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002665 flags = flags_save;
2666 if (!ISSET(MODIFIED)) {
2667 titlebar(NULL);
2668 wrefresh(topwin);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002669 }
2670 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002671 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002672 cutbuffer = cutbuffer_save;
2673 blank_statusbar_refresh();
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002674 /* Display the shortcut list with UnCut. */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002675 shortcut_init(0);
2676 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002677
Chris Allegretta6df90f52002-07-19 01:08:59 +00002678 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002679}
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002680
2681int do_justify_void(void)
2682{
2683 return do_justify(FALSE);
2684}
2685
2686int do_full_justify(void)
2687{
2688 return do_justify(TRUE);
2689}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00002690#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002691
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002692int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002693{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002694 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002695
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002696 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002697
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002698#ifdef ENABLE_MULTIBUFFER
2699 if (!close_open_file()) {
2700 display_main_list();
2701 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002702 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002703 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002704#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002705 finish(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00002706 }
2707
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002708 if (ISSET(TEMP_OPT))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002709 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002710 else
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002711 i = do_yesno(FALSE, _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002712
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002713#ifdef DEBUG
2714 dump_buffer(fileage);
2715#endif
2716
2717 if (i == 1) {
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002718 if (do_writeout(TRUE) > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002719
2720#ifdef ENABLE_MULTIBUFFER
2721 if (!close_open_file()) {
2722 display_main_list();
2723 return 1;
2724 }
2725 else
2726#endif
2727 finish(0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002728 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002729 } else if (i == 0) {
2730
2731#ifdef ENABLE_MULTIBUFFER
2732 if (!close_open_file()) {
2733 display_main_list();
2734 return 1;
2735 }
2736 else
2737#endif
2738 finish(0);
2739 } else
2740 statusbar(_("Cancelled"));
2741
2742 display_main_list();
2743 return 1;
2744}
2745
2746void signal_init(void)
2747{
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002748 /* Trap SIGINT and SIGQUIT because we want them to do useful
2749 * things. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002750 memset(&act, 0, sizeof(struct sigaction));
2751 act.sa_handler = SIG_IGN;
2752 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00002753 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002754
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002755 /* Trap SIGHUP and SIGTERM because we want to write the file out. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002756 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002757 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002758 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002759
2760#ifndef NANO_SMALL
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002761 /* Trap SIGWINCH because we want to handle window resizes. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002762 act.sa_handler = handle_sigwinch;
2763 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002764 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002765#endif
2766
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002767 /* Trap normal suspend (^Z) so we can handle it ourselves. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002768 if (!ISSET(SUSPEND)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002769 act.sa_handler = SIG_IGN;
2770 sigaction(SIGTSTP, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002771 } else {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002772 /* Block all other signals in the suspend and continue handlers.
2773 * If we don't do this, other stuff interrupts them! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002774 sigfillset(&act.sa_mask);
2775
2776 act.sa_handler = do_suspend;
2777 sigaction(SIGTSTP, &act, NULL);
2778
2779 act.sa_handler = do_cont;
2780 sigaction(SIGCONT, &act, NULL);
2781 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002782}
2783
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002784/* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002785RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002786{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002787 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002788}
2789
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002790/* Handler for SIGTSTP (suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002791RETSIGTYPE do_suspend(int signal)
2792{
2793 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002794 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002795 fflush(stdout);
2796
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002797 /* Restore the old terminal settings. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002798 tcsetattr(0, TCSANOW, &oldterm);
2799
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002800 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002801 * suspended. */
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002802 act.sa_handler = handle_hupterm;
2803 sigaction(SIGHUP, &act, NULL);
2804 sigaction(SIGTERM, &act, NULL);
2805
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002806 /* Do what mutt does: send ourselves a SIGSTOP. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002807 kill(0, SIGSTOP);
2808}
2809
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002810/* Handler for SIGCONT (continue after suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002811RETSIGTYPE do_cont(int signal)
2812{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002813#ifndef NANO_SMALL
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002814 /* Perhaps the user resized the window while we slept. Handle it
2815 * and update the screen in the process. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002816 handle_sigwinch(0);
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002817#else
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002818 /* Just update the screen. */
2819 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002820#endif
2821}
2822
2823#ifndef NANO_SMALL
2824void handle_sigwinch(int s)
2825{
2826 const char *tty = ttyname(0);
2827 int fd;
2828 int result = 0;
2829 struct winsize win;
2830
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002831 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002832 return;
2833 fd = open(tty, O_RDWR);
2834 if (fd == -1)
2835 return;
2836 result = ioctl(fd, TIOCGWINSZ, &win);
2837 close(fd);
2838 if (result == -1)
2839 return;
2840
2841 /* Could check whether the COLS or LINES changed, and return
2842 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2843 * variables, and in some cases ncurses has already updated them.
2844 * But not in all cases, argh. */
2845 COLS = win.ws_col;
2846 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002847 editwinrows = LINES - 5 + no_help();
2848 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002849 die_too_small();
2850
2851#ifndef DISABLE_WRAPJUSTIFY
2852 fill = wrap_at;
2853 if (fill <= 0)
2854 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002855 if (fill < 0)
2856 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002857#endif
2858
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002859 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002860 memset(hblank, ' ', COLS);
2861 hblank[COLS] = '\0';
2862
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002863#ifdef USE_SLANG
2864 /* Slang curses emulation brain damage, part 1: If we just do what
2865 * curses does here, it'll only work properly if the resize made the
2866 * window smaller. Do what mutt does: Leave and immediately reenter
2867 * Slang screen management mode. */
2868 SLsmg_reset_smg();
2869 SLsmg_init_smg();
2870#else
2871 /* Do the equivalent of what Minimum Profit does: Leave and
2872 * immediately reenter curses mode. */
2873 endwin();
2874 refresh();
2875#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002876
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002877 /* Do the equivalent of what both mutt and Minimum Profit do:
2878 * Reinitialize all the windows based on the new screen
2879 * dimensions. */
2880 window_init();
2881
2882 /* Redraw the contents of the windows that need it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002883 blank_statusbar();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002884 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002885 total_refresh();
2886
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002887 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002888 curs_set(1);
2889
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002890 /* Restore the terminal to its previously saved state. */
2891 resetty();
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002892
2893 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002894 siglongjmp(jmpbuf, 1);
2895}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002896
2897void allow_pending_sigwinch(int allow)
2898{
2899 sigset_t winch;
2900 sigemptyset(&winch);
2901 sigaddset(&winch, SIGWINCH);
2902 if (allow)
2903 sigprocmask(SIG_UNBLOCK, &winch, NULL);
2904 else
2905 sigprocmask(SIG_BLOCK, &winch, NULL);
2906}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002907#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002908
Chris Allegrettadab017e2002-04-23 10:56:06 +00002909#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002910void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002911{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002912 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002913
Chris Allegretta658399a2001-06-14 02:54:22 +00002914 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002915 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002916
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002917 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002918 case TOGGLE_SUSPEND_KEY:
2919 signal_init();
2920 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002921#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00002922 case TOGGLE_MOUSE_KEY:
2923 mouse_init();
2924 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002925#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002926 case TOGGLE_NOHELP_KEY:
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002927 blank_statusbar();
2928 blank_bottombars();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002929 wrefresh(bottomwin);
2930 window_init();
2931 edit_refresh();
2932 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002933 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002934 case TOGGLE_DOS_KEY:
2935 UNSET(MAC_FILE);
2936 break;
2937 case TOGGLE_MAC_KEY:
2938 UNSET(DOS_FILE);
2939 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002940#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002941 case TOGGLE_SYNTAX_KEY:
2942 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002943 break;
2944#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002945 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002946
Chris Allegretta6df90f52002-07-19 01:08:59 +00002947 /* We are assuming here that shortcut_init() above didn't free and
2948 * reallocate the toggles. */
2949 enabled = ISSET(which->flag);
2950 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2951 enabled = !enabled;
2952 statusbar("%s %s", which->desc,
2953 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002954}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002955#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002956
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002957#if !defined(NANO_SMALL) || defined(USE_SLANG)
2958void disable_signals(void)
2959{
2960 struct termios term;
2961
2962 tcgetattr(0, &term);
2963 term.c_lflag &= ~ISIG;
2964 tcsetattr(0, TCSANOW, &term);
2965}
2966#endif
2967
2968#ifndef NANO_SMALL
2969void enable_signals(void)
2970{
2971 struct termios term;
2972
2973 tcgetattr(0, &term);
2974 term.c_lflag |= ISIG;
2975 tcsetattr(0, TCSANOW, &term);
2976}
2977#endif
2978
2979void disable_flow_control(void)
2980{
2981 struct termios term;
2982
2983 tcgetattr(0, &term);
2984 term.c_iflag &= ~(IXON|IXOFF);
2985 tcsetattr(0, TCSANOW, &term);
2986}
2987
2988void enable_flow_control(void)
2989{
2990 struct termios term;
2991
2992 tcgetattr(0, &term);
2993 term.c_iflag |= (IXON|IXOFF);
2994 tcsetattr(0, TCSANOW, &term);
2995}
2996
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002997int main(int argc, char *argv[])
2998{
2999 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003000 int startline = 0; /* Line to try and start at */
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003001 int modify_control_seq = 0;
Chris Allegretta09fc4302003-01-16 22:16:38 +00003002 int fill_flag_used = 0; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003003 const shortcut *s;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003004 int keyhandled = 0; /* Have we handled the keystroke yet? */
David Lawrence Ramseyf8ddf312004-01-09 22:38:09 +00003005 int kbinput; /* Input from keyboard */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003006 int meta_key;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003007
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003008#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003009 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003010#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003011#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003012 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003013 {"help", 0, 0, 'h'},
3014#ifdef ENABLE_MULTIBUFFER
3015 {"multibuffer", 0, 0, 'F'},
3016#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003017#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003018#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003019 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003020#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003021 {"ignorercfiles", 0, 0, 'I'},
3022#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003023#ifndef DISABLE_JUSTIFY
3024 {"quotestr", 1, 0, 'Q'},
3025#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003026#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003027 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003028#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003029 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003030 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003031#ifdef ENABLE_COLOR
3032 {"syntax", 1, 0, 'Y'},
3033#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003034 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003035 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003036 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003037#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003038 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003039#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003040#ifndef DISABLE_OPERATINGDIR
3041 {"operatingdir", 1, 0, 'o'},
3042#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003043 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003044#ifndef DISABLE_WRAPJUSTIFY
3045 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003046#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003047#ifndef DISABLE_SPELLER
3048 {"speller", 1, 0, 's'},
3049#endif
3050 {"tempfile", 0, 0, 't'},
3051 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003052#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003053 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003054#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003055 {"nohelp", 0, 0, 'x'},
3056 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003057#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003058 {"backup", 0, 0, 'B'},
3059 {"dos", 0, 0, 'D'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003060 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003061 {"mac", 0, 0, 'M'},
3062 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003063 {"smooth", 0, 0, 'S'},
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003064 {"restricted", 0, 0, 'Z'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003065 {"autoindent", 0, 0, 'i'},
3066 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003067#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003068 {0, 0, 0, 0}
3069 };
3070#endif
3071
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003072#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003073 setlocale(LC_ALL, "");
3074 bindtextdomain(PACKAGE, LOCALEDIR);
3075 textdomain(PACKAGE);
3076#endif
3077
Chris Allegretta7662c862003-01-13 01:35:15 +00003078#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003079 /* if we don't have rcfile support, we're root, and
3080 --disable-wrapping-as-root is used, turn wrapping off */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003081 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003082 SET(NO_WRAP);
3083#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003084
3085#ifdef HAVE_GETOPT_LONG
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003086 while ((optchr = getopt_long(argc, argv, "h?BDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz",
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003087 long_options, NULL)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003088#else
3089 while ((optchr =
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003090 getopt(argc, argv, "h?BDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003091#endif
3092
3093 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003094
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003095 case 'a':
3096 case 'b':
3097 case 'e':
3098 case 'f':
3099 case 'g':
3100 case 'j':
3101 /* Pico compatibility flags */
3102 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003103#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003104 case 'B':
3105 SET(BACKUP_FILE);
3106 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003107 case 'D':
3108 SET(DOS_FILE);
3109 break;
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003110 case 'E':
3111 backup_dir = mallocstrcpy(backup_dir, optarg);
3112 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003113#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003114#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003115 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003116 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003117 break;
3118#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003119#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003120#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003121 case 'H':
3122 SET(HISTORYLOG);
3123 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003124#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003125 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003126 SET(NO_RCFILE);
3127 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003128#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003129#ifndef NANO_SMALL
3130 case 'M':
3131 SET(MAC_FILE);
3132 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003133 case 'N':
3134 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003135 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003136#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003137#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003138 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003139 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003140 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003141#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003142#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003143 case 'R':
3144 SET(USE_REGEXP);
3145 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003146#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003147#ifndef NANO_SMALL
3148 case 'S':
3149 SET(SMOOTHSCROLL);
3150 break;
3151#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003152 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003153 {
3154 int i;
3155 char *first_error;
3156
Chris Allegretta7662c862003-01-13 01:35:15 +00003157 /* Using strtol() instead of atoi() lets us accept 0
3158 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003159 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003160 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003161 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003162 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003163 tabsize = i;
3164 if (tabsize <= 0) {
3165 fprintf(stderr, _("Tab size is too small for nano...\n"));
3166 exit(1);
3167 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003168 }
3169 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003170 case 'V':
3171 version();
3172 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003173#ifdef ENABLE_COLOR
3174 case 'Y':
3175 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3176 break;
3177#endif
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003178 case 'Z':
3179 SET(RESTRICTED);
3180 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003181 case 'c':
3182 SET(CONSTUPDATE);
3183 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003184 case 'd':
3185 SET(REBIND_DELETE);
3186 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003187#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003188 case 'i':
3189 SET(AUTOINDENT);
3190 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003191 case 'k':
3192 SET(CUT_TO_END);
3193 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003194#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003195 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003196 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003197 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003198#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003199 case 'm':
3200 SET(USE_MOUSE);
3201 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003202#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003203#ifndef DISABLE_OPERATINGDIR
3204 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003205 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003206 break;
3207#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003208 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003209 SET(PRESERVE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003210 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003211#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003212 case 'r':
3213 {
3214 int i;
3215 char *first_error;
3216
Chris Allegretta7662c862003-01-13 01:35:15 +00003217 /* Using strtol() instead of atoi() lets us accept 0
3218 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003219 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003220 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003221 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003222 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003223 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003224 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003225 fill_flag_used = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003226 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003227#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003228#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003229 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003230 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003231 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003232#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003233 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003234 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003235 break;
3236 case 'v':
3237 SET(VIEW_MODE);
3238 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003239#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003240 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003241 SET(NO_WRAP);
3242 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003243#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003244 case 'x':
3245 SET(NO_HELP);
3246 break;
3247 case 'z':
3248 SET(SUSPEND);
3249 break;
3250 default:
3251 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003252 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003253 }
3254
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003255 /* If filename starts with 'r', we use restricted mode. */
3256 if (*(tail(argv[0])) == 'r')
3257 SET(RESTRICTED);
3258
3259 /* If we're using restricted mode, disable suspending, backup files,
3260 * and reading rcfiles. */
3261 if (ISSET(RESTRICTED)) {
3262 UNSET(SUSPEND);
3263 UNSET(BACKUP_FILE);
3264 SET(NO_RCFILE);
3265 }
3266
Chris Allegretta7662c862003-01-13 01:35:15 +00003267/* We've read through the command line options. Now back up the flags
3268 and values that are set, and read the rcfile(s). If the values
3269 haven't changed afterward, restore the backed-up values. */
3270#ifdef ENABLE_NANORC
3271 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003272#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003273 char *operating_dir_cpy = operating_dir;
3274#endif
3275#ifndef DISABLE_WRAPPING
3276 int wrap_at_cpy = wrap_at;
3277#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003278#ifndef NANO_SMALL
3279 char *backup_dir_cpy = backup_dir;
3280#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003281#ifndef DISABLE_JUSTIFY
3282 char *quotestr_cpy = quotestr;
3283#endif
3284#ifndef DISABLE_SPELLER
3285 char *alt_speller_cpy = alt_speller;
3286#endif
3287 int tabsize_cpy = tabsize;
3288 long flags_cpy = flags;
3289
Chris Allegretta5ec68622003-02-05 02:39:34 +00003290#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003291 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003292#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003293#ifndef NANO_SMALL
3294 backup_dir = NULL;
3295#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003296#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003297 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003298#endif
3299#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003300 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003301#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003302
3303 do_rcfile();
3304
3305#ifndef DISABLE_OPERATINGDIR
3306 if (operating_dir_cpy != NULL) {
3307 free(operating_dir);
3308 operating_dir = operating_dir_cpy;
3309 }
3310#endif
3311#ifndef DISABLE_WRAPPING
3312 if (fill_flag_used)
3313 wrap_at = wrap_at_cpy;
3314#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003315#ifndef NANO_SMALL
3316 if (backup_dir_cpy != NULL) {
3317 free(backup_dir);
3318 backup_dir = backup_dir_cpy;
3319 }
3320#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003321#ifndef DISABLE_JUSTIFY
3322 if (quotestr_cpy != NULL) {
3323 free(quotestr);
3324 quotestr = quotestr_cpy;
3325 }
3326#endif
3327#ifndef DISABLE_SPELLER
3328 if (alt_speller_cpy != NULL) {
3329 free(alt_speller);
3330 alt_speller = alt_speller_cpy;
3331 }
3332#endif
3333 if (tabsize_cpy > 0)
3334 tabsize = tabsize_cpy;
3335 flags |= flags_cpy;
3336 }
3337#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003338 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003339 SET(NO_WRAP);
3340#endif
3341#endif /* ENABLE_NANORC */
3342
Chris Allegrettad8451932003-03-11 03:50:40 +00003343#ifndef NANO_SMALL
3344 history_init();
3345#ifdef ENABLE_NANORC
3346 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3347 load_history();
3348#endif
3349#endif
3350
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003351#ifndef NANO_SMALL
3352 /* Set up the backup directory. This entails making sure it exists
3353 * and is a directory, so that backup files will be saved there. */
3354 init_backup_dir();
3355#endif
3356
Chris Allegretta7662c862003-01-13 01:35:15 +00003357#ifndef DISABLE_OPERATINGDIR
3358 /* Set up the operating directory. This entails chdir()ing there,
3359 so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003360 init_operating_dir();
3361#endif
3362
Chris Allegretta7662c862003-01-13 01:35:15 +00003363#ifndef DISABLE_JUSTIFY
3364 if (quotestr == NULL)
3365#ifdef HAVE_REGEX_H
3366 quotestr = mallocstrcpy(NULL, "^([ \t]*[|>:}#])+");
3367#else
3368 quotestr = mallocstrcpy(NULL, "> ");
3369#endif
3370#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003371
Chris Allegretta7662c862003-01-13 01:35:15 +00003372 if (tabsize == -1)
3373 tabsize = 8;
3374
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003375 /* Clear the filename we'll be using */
3376 filename = charalloc(1);
3377 filename[0] = '\0';
3378
Chris Allegretta7662c862003-01-13 01:35:15 +00003379 /* If there's a +LINE flag, it is the first non-option argument. */
3380 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3381 startline = atoi(&argv[optind][1]);
3382 optind++;
3383 }
3384 if (0 < optind && optind < argc)
3385 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003386
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003387 /* See if there's a non-option in argv (first non-option is the
3388 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003389 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003390 /* Look for the +line flag... */
3391 if (argv[optind][0] == '+') {
3392 startline = atoi(&argv[optind][1]);
3393 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003394 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003395 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003396 } else
3397 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003398 }
3399
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003400 /* Back up the old terminal settings so that they can be restored. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003401 tcgetattr(0, &oldterm);
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003402
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003403 /* Curses initialization stuff: Start curses, save the state of the
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003404 * terminal mode, put the terminal in raw mode (read one character at
3405 * a time and don't interpret the special control keys), disable
3406 * translation of carriage return (^M) into newline (^J) so that we
3407 * can tell the difference between the Enter key and ^J, and disable
3408 * echoing of characters as they're typed. Finally, if we're in
3409 * preserve mode, turn the flow control characters back on. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003410 initscr();
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003411 raw();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003412#ifdef USE_SLANG
3413 /* Slang curses emulation brain damage, part 2: Raw mode acts just
3414 * like cbreak mode here and doesn't disable interpretation of the
3415 * special control keys. Work around this by manually disabling
3416 * interpretation of the special control keys. */
3417 disable_signals();
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003418#endif
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003419 nonl();
David Lawrence Ramseyd03216a2004-01-28 18:21:21 +00003420 noecho();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003421 if (ISSET(PRESERVE))
3422 enable_flow_control();
3423
3424#ifndef NANO_SMALL
3425 /* Save the terminal's current state, so that we can restore it
3426 * after a resize. */
3427 savetty();
3428#endif
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003429
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003430 /* Set up the global variables and the shortcuts. */
Chris Allegretta56214c62001-09-27 02:46:53 +00003431 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003432 shortcut_init(0);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003433
3434 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003435 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003436
3437#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003438 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003439#endif
3440
Chris Allegretta2a42af12000-09-12 23:02:49 +00003441 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003442#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003443 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003444#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003445
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003446#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003447 fprintf(stderr, "Main: bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003448#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003449 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003450 display_main_list();
3451
3452#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003453 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003454#endif
3455
David Lawrence Ramsey97133f52004-05-14 17:39:19 +00003456 open_file(filename, 0, 0);
Chris Allegretta7662c862003-01-13 01:35:15 +00003457#ifdef ENABLE_MULTIBUFFER
3458 /* If we're using multibuffers and more than one file is specified
3459 on the command line, load them all and switch to the first one
3460 afterward */
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003461 if (optind + 1 < argc) {
3462 int old_multibuffer = ISSET(MULTIBUFFER);
3463 SET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003464 for (optind++; optind < argc; optind++) {
3465 add_open_file(1);
3466 new_file();
3467 filename = mallocstrcpy(filename, argv[optind]);
3468 open_file(filename, 0, 0);
3469 load_file(0);
3470 }
3471 open_nextfile_void();
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003472 if (!old_multibuffer)
3473 UNSET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003474 }
3475#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003476
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003477 titlebar(NULL);
3478
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003479 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003480 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003481
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003482#ifndef NANO_SMALL
3483 /* Return here after a SIGWINCH. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003484 sigsetjmp(jmpbuf, 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003485#endif
Chris Allegretta08020882001-01-29 23:37:54 +00003486
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003487 /* SHUT UP GCC! */
3488 startline = 0;
3489 fill_flag_used = 0;
3490 keyhandled = 0;
3491
Chris Allegretta7662c862003-01-13 01:35:15 +00003492 /* This variable should be initialized after the sigsetjmp(), so we
3493 can't do Esc-Esc then quickly resize and muck things up. */
Chris Allegretta08020882001-01-29 23:37:54 +00003494 modify_control_seq = 0;
3495
Robert Siemborski6967eec2000-07-08 14:23:32 +00003496 edit_refresh();
3497 reset_cursor();
3498
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003499 while (TRUE) {
Chris Allegrettad0845df2003-02-13 00:56:57 +00003500 keyhandled = 0;
Chris Allegretta9239d742000-09-06 15:19:18 +00003501
Chris Allegrettad26ab912003-01-28 01:16:47 +00003502 if (ISSET(CONSTUPDATE))
3503 do_cursorpos(1);
3504
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003505#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003506 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003507#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003508
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003509 kbinput = get_kbinput(edit, &meta_key);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003510#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003511 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003512#endif
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003513 if (meta_key == TRUE) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003514 /* Check for the metaval and miscval defs... */
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003515 for (s = main_list; s != NULL; s = s->next)
David Lawrence Ramsey82138502003-12-24 08:03:54 +00003516 if ((s->metaval != NANO_NO_KEY && kbinput == s->metaval) ||
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003517 (s->miscval != NANO_NO_KEY && kbinput == s->miscval)) {
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003518 if (ISSET(VIEW_MODE) && !s->viewok)
3519 print_view_warning();
3520 else {
3521 if (s->func != do_cut_text)
3522 UNSET(KEEP_CUTBUFFER);
3523 s->func();
3524 }
3525 keyhandled = 1;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003526 }
3527#ifndef NANO_SMALL
3528 if (!keyhandled)
3529 /* And for toggle switches */
3530 for (t = toggles; t != NULL; t = t->next)
3531 if (kbinput == t->val) {
3532 UNSET(KEEP_CUTBUFFER);
3533 do_toggle(t);
3534 keyhandled = 1;
3535 }
3536#endif
3537#ifdef DEBUG
3538 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput,
3539 kbinput);
3540#endif
3541 }
3542
3543 /* Look through the main shortcut list to see if we've hit a
3544 shortcut key or function key */
3545
3546 if (!keyhandled)
3547#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
3548 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
3549#else
3550 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
3551#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003552 if ((s->ctrlval != NANO_NO_KEY && kbinput == s->ctrlval) ||
3553 (s->funcval != NANO_NO_KEY && kbinput == s->funcval)) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003554 if (ISSET(VIEW_MODE) && !s->viewok)
3555 print_view_warning();
3556 else {
3557 if (s->func != do_cut_text)
3558 UNSET(KEEP_CUTBUFFER);
3559 s->func();
3560 }
3561 keyhandled = 1;
3562 /* Break out explicitly once we successfully handle
3563 a shortcut */
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003564 break;
3565 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003566 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003567
3568 if (!keyhandled)
3569 UNSET(KEEP_CUTBUFFER);
Chris Allegrettae42df732002-10-15 00:27:55 +00003570
Chris Allegrettae42df732002-10-15 00:27:55 +00003571 /* Don't even think about changing this string */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003572 if (kbinput == NANO_CONTROL_Q)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003573 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003574 if (kbinput == NANO_CONTROL_S)
3575 statusbar(_("XOFF ignored, mumble mumble."));
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003576
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003577 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3578 Control-S and Control-Q */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003579 if (kbinput == NANO_CONTROL_Q || kbinput == NANO_CONTROL_S)
Chris Allegretta9239d742000-09-06 15:19:18 +00003580 keyhandled = 1;
3581
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003582 /* Catch ^Z by hand when triggered also */
3583 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003584 if (ISSET(SUSPEND))
3585 do_suspend(0);
3586 keyhandled = 1;
3587 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003588
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003589 /* Last gasp, stuff that's not in the main lists */
3590 if (!keyhandled)
3591 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003592#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003593 case KEY_MOUSE:
3594 do_mouse();
3595 break;
3596#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003597
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003598 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3599 * have been handled before we
3600 * got here */
3601 case NANO_CONTROL_5: /* Ctrl-] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003602 break;
3603 default:
3604#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003605 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003606#endif
3607 /* We no longer stop unhandled sequences so that people with
3608 odd character sets can type... */
3609
Chris Allegretta7662c862003-01-13 01:35:15 +00003610 if (ISSET(VIEW_MODE))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003611 print_view_warning();
Chris Allegretta7662c862003-01-13 01:35:15 +00003612 else
3613 do_char(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003614 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003615
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003616 reset_cursor();
3617 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003618 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003619 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003620}