blob: 1362890e69a5a0f725d7a264dbcf9c733df6b0b2 [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
David Lawrence Ramseyda141062004-05-25 19:41:11 +000075/* What we do when we're all set to exit. */
76void finish(void)
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
David Lawrence Ramseyda141062004-05-25 19:41:11 +000098 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000099}
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')
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +0000175 i = write_file(ret, TRUE, FALSE, TRUE);
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 Ramseyc7acf692004-05-22 20:15:20 +0000636 print1opt("-A", "--smarthome", _("Enable smart home key"));
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000637 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000638 print1opt("-D", "--dos", _("Write file in DOS format"));
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +0000639 print1opt("-E", "--backupdir=[dir]", _("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000640#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000641#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000642 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000643#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000644#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000645#ifndef NANO_SMALL
Chris Allegretta36fec722003-01-22 01:13:25 +0000646 print1opt("-H", "--historylog", _("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000647#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000648 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
649#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000650#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000651 print1opt("-M", "--mac", _("Write file in Mac format"));
652 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000653#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000654#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000655 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000656#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000657#ifdef HAVE_REGEX_H
658 print1opt("-R", "--regexp", _("Do regular expression searches"));
659#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000660#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000661 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000662#endif
David Lawrence Ramseya7c93642004-02-25 03:19:29 +0000663 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), _("Set width of a tab in cols to #cols"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000664 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000665#ifdef ENABLE_COLOR
666 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
667#endif
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000668 print1opt(_("-Z"), _("--restricted"), _("Restricted mode"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000669 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000670#ifndef NANO_SMALL
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000671 print1opt("-d", "--rebinddelete", _("Fix Backspace/Delete confusion problem"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000672 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
673 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000674#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000675 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000676#ifndef DISABLE_MOUSE
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000677 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000678#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000679#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000680 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000681#endif
Jordi Mallacheeb50042003-01-18 22:42:34 +0000682 print1opt("-p", "--preserve", _("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000683#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000684 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000685#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000686#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000687 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000688#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000689 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
690 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000691#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000692 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000693#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000694 print1opt("-x", "--nohelp", _("Don't show help window"));
695 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000696
697 /* this is a special case */
698 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000699
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000700 exit(0);
701}
702
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000703void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000704{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000705 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000706 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000707 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000708 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000709 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000710
Chris Allegrettae6600372003-01-17 03:39:41 +0000711#ifndef ENABLE_NLS
712 printf(" --disable-nls");
713#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000714#ifdef DEBUG
715 printf(" --enable-debug");
716#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000717#ifdef NANO_EXTRA
718 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000719#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000720#ifdef NANO_SMALL
721 printf(" --enable-tiny");
722#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000723#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000724 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000725#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000726#ifdef DISABLE_HELP
727 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000728#endif
729#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000730 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000731#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000732#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +0000733 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000734#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000735#ifdef DISABLE_OPERATINGDIR
736 printf(" --disable-operatingdir");
737#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000738#ifdef DISABLE_SPELLER
739 printf(" --disable-speller");
740#endif
741#ifdef DISABLE_TABCOMP
742 printf(" --disable-tabcomp");
743#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000744#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000745#ifdef DISABLE_WRAPPING
746 printf(" --disable-wrapping");
747#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000748#ifdef DISABLE_ROOTWRAP
749 printf(" --disable-wrapping-as-root");
750#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000751#ifdef ENABLE_COLOR
752 printf(" --enable-color");
753#endif
754#ifdef ENABLE_MULTIBUFFER
755 printf(" --enable-multibuffer");
756#endif
757#ifdef ENABLE_NANORC
758 printf(" --enable-nanorc");
759#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000760#ifdef USE_SLANG
761 printf(" --with-slang");
762#endif
763 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000764}
765
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000766int no_help(void)
767{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000768 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000769}
770
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000771int nano_disabled_msg(void)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000772{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000773 statusbar(_("Sorry, support for this function has been disabled"));
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000774 return 1;
Chris Allegrettaff269f82000-12-01 18:46:01 +0000775}
776
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000777#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000778static int pid; /* This is the PID of the newly forked process
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000779 * below. It must be global since the signal
780 * handler needs it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000781RETSIGTYPE cancel_fork(int signal)
782{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000783 if (kill(pid, SIGKILL) == -1)
784 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000785}
786
787int open_pipe(const char *command)
788{
789 int fd[2];
790 FILE *f;
791 struct sigaction oldaction, newaction;
792 /* original and temporary handlers for SIGINT */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000793 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000794 /* cancel_sigs == 1 means that sigaction() failed without changing
795 * the signal handlers. cancel_sigs == 2 means the signal handler
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000796 * was changed, but the tcsetattr() didn't succeed.
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000797 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000798 * I use this variable since it is important to put things back when
799 * we finish, even if we get errors. */
800
801 /* Make our pipes. */
802
803 if (pipe(fd) == -1) {
804 statusbar(_("Could not pipe"));
805 return 1;
806 }
807
808 /* Fork a child. */
809
810 if ((pid = fork()) == 0) {
811 close(fd[0]);
812 dup2(fd[1], fileno(stdout));
813 dup2(fd[1], fileno(stderr));
814 /* If execl() returns at all, there was an error. */
815
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000816 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000817 exit(0);
818 }
819
820 /* Else continue as parent. */
821
822 close(fd[1]);
823
824 if (pid == -1) {
825 close(fd[0]);
826 statusbar(_("Could not fork"));
827 return 1;
828 }
829
830 /* Before we start reading the forked command's output, we set
831 * things up so that ^C will cancel the new process. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000832
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000833 /* Enable interpretation of the special control keys so that we get
834 * SIGINT when Ctrl-C is pressed. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000835 enable_signals();
836
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000837 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000838 cancel_sigs = 1;
839 nperror("sigaction");
840 } else {
841 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000842 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000843 cancel_sigs = 1;
844 nperror("sigaction");
845 }
846 }
847 /* Note that now oldaction is the previous SIGINT signal handler,
848 * to be restored later. */
849
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000850 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000851 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000852 nperror("fdopen");
853
854 read_file(f, "stdin", 0);
855 /* if multibuffer mode is on, we could be here in view mode; if so,
856 don't set the modification flag */
857 if (!ISSET(VIEW_MODE))
858 set_modified();
859
860 if (wait(NULL) == -1)
861 nperror("wait");
862
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000863 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000864 nperror("sigaction");
865
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000866 /* Disable interpretation of the special control keys so that we can
867 * use Ctrl-C for other things. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000868 disable_signals();
869
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000870 return 0;
871}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +0000872#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000873
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000874#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000875void do_mouse(void)
876{
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000877 int mouse_x, mouse_y;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000878
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000879 if (get_mouseinput(&mouse_x, &mouse_y, 1) == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000880
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000881 /* Click in the edit window to move the cursor, but only when
882 we're not in a subfunction. */
883 if (wenclose(edit, mouse_y, mouse_x) && currshortcut == main_list) {
884 int sameline;
885 /* Did they click on the line with the cursor? If they
886 clicked on the cursor, we set the mark. */
887 size_t xcur;
888 /* The character they clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000889
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000890 /* Subtract out size of topwin. Perhaps we need a constant
891 somewhere? */
892 mouse_y -= 2;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000893
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000894 sameline = (mouse_y == current_y);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000895
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000896 /* Move to where the click occurred. */
897 for (; current_y < mouse_y && current->next != NULL; current_y++)
898 current = current->next;
899 for (; current_y > mouse_y && current->prev != NULL; current_y--)
900 current = current->prev;
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000901
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000902 xcur = actual_x(current->data, get_page_start(xplustabs()) +
903 mouse_x);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000904
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000905 /* Selecting where the cursor is toggles the mark. As does
906 selecting beyond the line length with the cursor at the
907 end of the line. */
908 if (sameline && xcur == current_x) {
909 if (ISSET(VIEW_MODE)) {
910 print_view_warning();
911 return;
912 }
913 do_mark();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000914 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000915
916 current_x = xcur;
917 placewewant = xplustabs();
918 edit_refresh();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000919 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000920 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000921 /* FIXME: If we clicked on a location in the statusbar, the cursor
922 should move to the location we clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000923}
924#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000925
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000926/* The user typed a character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000927void do_char(char ch)
928{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000929 size_t current_len = strlen(current->data);
930#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000931 int do_refresh = FALSE;
932 /* Do we have to call edit_refresh(), or can we get away with
Chris Allegretta6df90f52002-07-19 01:08:59 +0000933 * update_line()? */
934#endif
935
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000936 if (ch == '\0') /* Null to newline, if needed. */
937 ch = '\n';
938 else if (ch == '\n') { /* Newline to Enter, if needed. */
939 do_enter();
940 return;
941 }
942
943 assert(current != NULL && current->data != NULL);
944
945 /* When a character is inserted on the current magicline, it means
946 * we need a new one! */
David Lawrence Ramseyb9775152004-03-19 02:15:42 +0000947 if (filebot == current)
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000948 new_magicline();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000949
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000950 /* More dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000951 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000952 assert(current_x <= current_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000953 charmove(&current->data[current_x + 1], &current->data[current_x],
954 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000955 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000956 totsize++;
957 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000958
Chris Allegretta6df90f52002-07-19 01:08:59 +0000959#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000960 /* Note that current_x has not yet been incremented. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000961 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000962 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +0000963#endif
964
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000965 do_right(FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000966
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000967#ifndef DISABLE_WRAPPING
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000968 /* If we're wrapping text, we need to call edit_refresh(). */
Chris Allegrettadffa2072002-07-24 01:02:26 +0000969 if (!ISSET(NO_WRAP) && ch != '\t')
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000970 do_refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000971#endif
972
Chris Allegretta6df90f52002-07-19 01:08:59 +0000973#ifdef ENABLE_COLOR
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000974 /* If color syntaxes are turned on, we need to call
975 * edit_refresh(). */
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +0000976 if (ISSET(COLOR_SYNTAX))
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000977 do_refresh = TRUE;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000978#endif
979
980#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000981 if (do_refresh)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000982 edit_refresh();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000983 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000984#endif
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000985 update_line(current, current_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000986}
987
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000988int do_verbatim_input(void)
989{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000990 int *v_kbinput = NULL; /* Used to hold verbatim input. */
991 size_t v_len; /* Length of verbatim input. */
David Lawrence Ramsey805547f2004-04-22 03:41:04 +0000992 size_t i;
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000993
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000994 statusbar(_("Verbatim input"));
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000995
996 v_kbinput = get_verbatim_kbinput(edit, v_kbinput, &v_len, TRUE);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000997
998 /* Turn on DISABLE_CURPOS while inserting character(s) and turn it
999 * off afterwards, so that if constant cursor position display is
1000 * on, it will be updated properly. */
1001 SET(DISABLE_CURPOS);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001002 for (i = 0; i < v_len; i++)
1003 do_char((char)v_kbinput[i]);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001004 UNSET(DISABLE_CURPOS);
1005
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001006 free(v_kbinput);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001007
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001008 return 1;
1009}
1010
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001011int do_backspace(void)
1012{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001013 if (current != fileage || current_x > 0) {
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001014 do_left(FALSE);
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001015 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001016 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001017 return 1;
1018}
1019
1020int do_delete(void)
1021{
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001022 int do_refresh = FALSE;
1023 /* Do we have to call edit_refresh(), or can we get away with
1024 * update_line()? */
1025
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001026 assert(current != NULL && current->data != NULL && current_x <=
1027 strlen(current->data));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001028
1029 placewewant = xplustabs();
1030
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001031 if (current->data[current_x] != '\0') {
1032 size_t linelen = strlen(current->data + current_x);
1033
1034 assert(current_x < strlen(current->data));
1035
1036 /* Let's get dangerous. */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001037 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001038 linelen);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001039
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001040 null_at(&current->data, linelen + current_x - 1);
1041#ifndef NANO_SMALL
1042 if (current_x < mark_beginx && mark_beginbuf == current)
1043 mark_beginx--;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001044#endif
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001045 } else if (current != filebot && (current->next != filebot ||
1046 current->data[0] == '\0')) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001047 /* We can delete the line before filebot only if it is blank: it
David Lawrence Ramsey32d19ce2004-05-24 05:05:07 +00001048 * becomes the new magicline then. */
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001049 filestruct *foo = current->next;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001050
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001051 assert(current_x == strlen(current->data));
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001052
1053 /* If we're deleting at the end of a line, we need to call
1054 * edit_refresh(). */
1055 if (current->data[current_x] == '\0')
1056 do_refresh = TRUE;
1057
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001058 current->data = charealloc(current->data, current_x +
1059 strlen(foo->data) + 1);
1060 strcpy(current->data + current_x, foo->data);
1061#ifndef NANO_SMALL
1062 if (mark_beginbuf == current->next) {
1063 mark_beginx += current_x;
1064 mark_beginbuf = current;
1065 }
1066#endif
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001067 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001068 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001069
1070 unlink_node(foo);
1071 delete_node(foo);
1072 renumber(current);
1073 totlines--;
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001074 wrap_reset();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001075 } else
1076 return 0;
1077
1078 totsize--;
1079 set_modified();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001080
1081#ifdef ENABLE_COLOR
1082 /* If color syntaxes are turned on, we need to call
1083 * edit_refresh(). */
1084 if (ISSET(COLOR_SYNTAX))
1085 do_refresh = TRUE;
1086#endif
1087
1088 if (do_refresh)
1089 edit_refresh();
1090 else
1091 update_line(current, current_x);
1092
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001093 return 1;
1094}
1095
1096int do_tab(void)
1097{
1098 do_char('\t');
1099 return 1;
1100}
1101
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001102/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001103int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001104{
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001105 filestruct *newnode = make_new_node(current);
1106 size_t extra = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001107
Chris Allegretta6df90f52002-07-19 01:08:59 +00001108 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001109
Chris Allegrettaff989832001-09-17 13:48:00 +00001110#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001111 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001112 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001113 /* If we are breaking the line in the indentation, the new
1114 * indentation should have only current_x characters, and
1115 * current_x should not change. */
1116 extra = indent_length(current->data);
1117 if (extra > current_x)
Chris Allegrettadab017e2002-04-23 10:56:06 +00001118 extra = current_x;
Chris Allegrettadab017e2002-04-23 10:56:06 +00001119 totsize += extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001120 }
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001121#endif
1122 newnode->data = charalloc(strlen(current->data + current_x) +
1123 extra + 1);
1124 strcpy(&newnode->data[extra], current->data + current_x);
1125#ifndef NANO_SMALL
1126 if (ISSET(AUTOINDENT))
1127 strncpy(newnode->data, current->data, extra);
1128#endif
1129 null_at(&current->data, current_x);
1130#ifndef NANO_SMALL
1131 if (current == mark_beginbuf && current_x < mark_beginx) {
1132 mark_beginbuf = newnode;
1133 mark_beginx += extra - current_x;
1134 }
1135#endif
1136 current_x = extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001137
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001138 if (current == filebot)
Chris Allegrettae3167732001-03-18 16:59:34 +00001139 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001140 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001141
1142 totsize++;
1143 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001144 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001145
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001146#ifndef NANO_SMALL
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001147 /* If we're in smooth scrolling mode and we're on the last line of
1148 * the edit window, move edittop down one line so that current is
1149 * onscreen. This prevents edit_refresh() from centering the
1150 * screen. */
1151 if (ISSET(SMOOTHSCROLL) && current_y == editwinrows - 1)
1152 edittop = edittop->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001153#endif
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001154 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001155
1156 totlines++;
1157 set_modified();
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001158 placewewant = xplustabs();
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001159
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001160 return 1;
1161}
1162
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001163#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001164int do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001165{
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001166 const filestruct *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001167 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001168
Chris Allegretta6df90f52002-07-19 01:08:59 +00001169 /* Skip letters in this word first. */
1170 while (current->data[current_x] != '\0' &&
1171 isalnum((int)current->data[current_x]))
1172 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001173
Chris Allegretta6df90f52002-07-19 01:08:59 +00001174 for (; current != NULL; current = current->next) {
1175 while (current->data[current_x] != '\0' &&
1176 !isalnum((int)current->data[current_x]))
1177 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001178
Chris Allegretta6df90f52002-07-19 01:08:59 +00001179 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001180 break;
1181
Chris Allegretta6df90f52002-07-19 01:08:59 +00001182 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001183 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001184 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001185 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001186
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001187 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001188
David Lawrence Ramseybf3c93e2004-03-13 19:42:58 +00001189 /* Refresh the screen. If current has run off the bottom, this
1190 * call puts it at the center line. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001191 edit_redraw(current_save);
David Lawrence Ramseybf3c93e2004-03-13 19:42:58 +00001192
Chris Allegretta6232d662002-05-12 19:52:15 +00001193 return 0;
1194}
1195
Chris Allegretta6df90f52002-07-19 01:08:59 +00001196/* The same thing for backwards. */
1197int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001198{
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001199 const filestruct *current_save = current;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001200 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001201
Chris Allegretta6df90f52002-07-19 01:08:59 +00001202 /* Skip letters in this word first. */
1203 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1204 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001205
Chris Allegretta6df90f52002-07-19 01:08:59 +00001206 for (; current != NULL; current = current->prev) {
1207 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1208 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001209
Chris Allegretta6df90f52002-07-19 01:08:59 +00001210 if (current_x >= 0)
1211 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001212
Chris Allegretta6df90f52002-07-19 01:08:59 +00001213 if (current->prev != NULL)
1214 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001215 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001216
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001217 if (current == NULL) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001218 current = fileage;
1219 current_x = 0;
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001220 } else {
1221 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1222 current_x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001223 }
1224
Chris Allegretta76e291b2001-10-14 19:05:10 +00001225 placewewant = xplustabs();
1226
David Lawrence Ramseyb6aa4282004-03-14 01:42:17 +00001227 /* Refresh the screen. If current has run off the top, this call
1228 * puts it at the center line. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001229 edit_redraw(current_save);
David Lawrence Ramseyb6aa4282004-03-14 01:42:17 +00001230
Chris Allegretta6232d662002-05-12 19:52:15 +00001231 return 0;
1232}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001233
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001234int do_mark(void)
1235{
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001236 TOGGLE(MARK_ISSET);
1237 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001238 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001239 mark_beginbuf = current;
1240 mark_beginx = current_x;
1241 } else {
1242 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001243 edit_refresh();
1244 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001245 return 1;
1246}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001247#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001248
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001249#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001250void wrap_reset(void)
1251{
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001252 same_line_wrap = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001253}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001254#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001255
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001256#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001257/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001258 * moved forward since the last typed character. Return value:
1259 * whether we wrapped. */
1260int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001261{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001262 size_t len = strlen(inptr->data); /* length of the line we wrap */
1263 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001264 int wrap_loc = -1; /* index of inptr->data where we wrap */
1265 int word_back = -1;
1266#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001267 const char *indentation = NULL;
1268 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001269 int indent_len = 0; /* strlen(indentation) */
1270#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001271 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001272 int after_break_len; /* strlen(after_break) */
1273 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001274 const char *wrap_line = NULL;
1275 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001276 int wrap_line_len = 0; /* strlen(wrap_line) */
1277 char *newline = NULL; /* the line we create */
1278 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001279
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001280/* There are three steps. First, we decide where to wrap. Then, we
1281 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001282
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001283/* Step 1, finding where to wrap. We are going to add a new-line
1284 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001285 * location of this replacement.
1286 *
1287 * Where should we break the line? We need the last "legal wrap point"
1288 * such that the last word before it ended at or before fill. If there
1289 * is no such point, we settle for the first legal wrap point.
1290 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001291 * A "legal wrap point" is a white-space character that is not followed by
1292 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001293 *
1294 * If there is no legal wrap point or we found the last character of the
1295 * line, we should return without wrapping.
1296 *
1297 * Note that the initial indentation does not count as a legal wrap
1298 * point if we are going to auto-indent!
1299 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001300 * Note that the code below could be optimised, by not calling strnlenpt()
1301 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001302
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001303#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001304 if (ISSET(AUTOINDENT))
1305 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001306#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001307 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001308 for (; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001309 /* record where the last word ended */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001310 if (!isblank(*wrap_line))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001311 word_back = i;
1312 /* if we have found a "legal wrap point" and the current word
1313 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001314 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001315 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001316 /* we record the latest "legal wrap point" */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001317 if (word_back != i && !isblank(wrap_line[1]))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001318 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001319 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001320 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001321 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001322
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001323/* Step 2, making the new wrap line. It will consist of indentation +
1324 * after_break + " " + wrap_line (although indentation and wrap_line are
1325 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001326
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001327 /* after_break is the text that will be moved to the next line. */
1328 after_break = inptr->data + wrap_loc + 1;
1329 after_break_len = len - wrap_loc - 1;
1330 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001331
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001332 /* new_line_len will later be increased by the lengths of indentation
1333 * and wrap_line. */
1334 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001335
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001336 /* We prepend the wrapped text to the next line, if the flag is set,
1337 * and there is a next line, and prepending would not make the line
1338 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001339 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001340 wrap_line = inptr->next->data;
1341 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001342
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001343 /* +1 for the space between after_break and wrap_line */
1344 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1345 wrapping = 1;
1346 new_line_len += (1 + wrap_line_len);
1347 }
1348 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001349
Chris Allegrettaff989832001-09-17 13:48:00 +00001350#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001351 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001352 /* Indentation comes from the next line if wrapping, else from
1353 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001354 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001355 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001356 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001357 /* The wrap_line text should not duplicate indentation.
1358 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001359 wrap_line += indent_len;
1360 else
1361 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001362 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001363#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001364
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001365 /* Now we allocate the new line and copy into it. */
1366 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1367 *newline = '\0';
1368
1369#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001370 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001371 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001372 newline[indent_len] = '\0';
1373 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001374#endif
1375 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001376 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001377 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001378 null_at(&inptr->data, wrap_loc + 1);
1379 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001380 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001381 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001382 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001383 * in a tab or a space, we don't add a space and decrement
1384 * totsize to account for that. */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001385 if (!isblank(newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001386 strcat(newline, " ");
1387 else
1388 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001389 strcat(newline, wrap_line);
1390 free(inptr->next->data);
1391 inptr->next->data = newline;
1392 } else {
1393 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001394
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001395 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001396 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001397#ifndef NANO_SMALL
1398 totsize += indent_len;
1399#endif
1400 totlines++;
1401 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001402 temp->prev = inptr;
1403 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001404 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001405 /* If temp->next is NULL, then temp is the last line of the
1406 * file, so we must set filebot. */
1407 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001408 temp->next->prev = temp;
1409 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001410 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001411 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001412
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001413/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1414 * other sundry things. */
1415
1416 /* later wraps of this line will be prepended to the next line. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001417 same_line_wrap = 1;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001418
1419 /* Each line knows its line number. We recalculate these if we
1420 * inserted a new line. */
1421 if (!wrapping)
1422 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001423
Chris Allegretta6df90f52002-07-19 01:08:59 +00001424 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001425 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001426 current = current->next;
1427 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001428#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001429 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001430#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001431 wrap_loc + 1;
1432 wrap_reset();
1433 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001434 }
1435
Chris Allegretta6df90f52002-07-19 01:08:59 +00001436#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001437 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001438 * If it was on the next line and we wrapped, we must move it
1439 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001440 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1441 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001442 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001443 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001444 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001445#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001446
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001447 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001448 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001449
1450 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001451}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001452#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001453
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001454#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001455/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001456 * return zero if the user cancels. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001457int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001458{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001459 char *save_search;
1460 char *save_replace;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001461 size_t current_x_save = current_x;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001462 filestruct *current_save = current;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001463 filestruct *edittop_save = edittop;
1464 /* Save where we are. */
1465 int i = 0;
1466 /* The return value. */
1467 int reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001468#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001469 int case_sens_set = ISSET(CASE_SENSITIVE);
1470 int mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001471
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001472 SET(CASE_SENSITIVE);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001473 /* Make sure the marking highlight is off during spell-check. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001474 UNSET(MARK_ISSET);
1475#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001476 /* Make sure spell-check goes forward only. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001477 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001478
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001479 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001480 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001481 save_search = last_search;
1482 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001483
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001484 /* Set search/replace strings to misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001485 last_search = mallocstrcpy(NULL, word);
1486 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001487
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001488 /* Start from the top of the file. */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001489 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001490 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001491
1492 search_last_line = FALSE;
1493
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001494 /* Find the first whole-word occurrence of word. */
1495 while (findnextstr(TRUE, TRUE, fileage, 0, word, FALSE) != 0)
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001496 if (is_whole_word(current_x, current->data, word)) {
1497 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001498
Chris Allegretta6df90f52002-07-19 01:08:59 +00001499 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001500
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001501 /* Allow the replace word to be corrected. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001502 i = statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001503#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001504 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001505#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001506 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001507
Chris Allegretta6df90f52002-07-19 01:08:59 +00001508 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001509
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001510 if (i != -1 && strcmp(word, answer)) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001511 search_last_line = FALSE;
1512 current_x--;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001513 do_replace_loop(word, current_save, &current_x_save, TRUE);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001514 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001515
1516 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001517 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001518
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001519 /* Restore the search/replace strings. */
1520 free(last_search);
1521 last_search = save_search;
1522 free(last_replace);
1523 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001524
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001525 /* Restore where we were. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001526 current = current_save;
1527 current_x = current_x_save;
1528 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001529
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001530 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001531 if (reverse_search_set)
1532 SET(REVERSE_SEARCH);
1533
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001534#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001535 if (!case_sens_set)
1536 UNSET(CASE_SENSITIVE);
1537
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001538 /* Restore marking highlight. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001539 if (mark_set)
1540 SET(MARK_ISSET);
1541#endif
1542
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001543 return i != -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001544}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001545
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001546/* Integrated spell checking using 'spell' program. Return value: NULL
1547 * for normal termination, otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001548const char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001549{
Chris Allegretta271e9722000-11-10 18:15:43 +00001550 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001551 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001552 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001553 pid_t pid_spell, pid_sort, pid_uniq;
1554 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001555
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001556 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001557 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1558 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001559
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001560 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001561
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001562 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001563 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001564
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001565 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001566
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001567 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001568
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001569 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001570 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1571 goto close_pipes_and_exit;
1572
1573 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1574 goto close_pipes_and_exit;
1575
Chris Allegretta271e9722000-11-10 18:15:43 +00001576 close(tempfile_fd);
1577
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001578 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001579 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1580 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001581
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001582 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001583
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001584 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001585 execlp("spell", "spell", NULL);
1586
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001587 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001588 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001589 }
1590
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001591 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001592 close(spell_fd[1]);
1593
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001594 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001595 if ((pid_sort = fork()) == 0) {
1596
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001597 /* Child continues (i.e, future spell process). Replace the
1598 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001599 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1600 goto close_pipes_and_exit;
1601
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001602 close(spell_fd[0]);
1603
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001604 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001605 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1606 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001607
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001608 close(sort_fd[1]);
1609
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001610 /* Start sort program. Use -f to remove mixed case without
1611 * having to have ANOTHER pipe for tr. If this isn't portable,
1612 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001613 execlp("sort", "sort", "-f", NULL);
1614
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001615 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001616 exit(1);
1617 }
1618
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001619 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001620 close(sort_fd[1]);
1621
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001622 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001623 if ((pid_uniq = fork()) == 0) {
1624
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001625 /* Child continues (i.e, future uniq process). Replace the
1626 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001627 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1628 goto close_pipes_and_exit;
1629
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001630 close(sort_fd[0]);
1631
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001632 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001633 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1634 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001635
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001636 close(uniq_fd[1]);
1637
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001638 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001639 execlp("uniq", "uniq", NULL);
1640
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001641 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001642 exit(1);
1643 }
1644
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001645 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001646 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001647
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001648 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001649 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1650 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001651 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001652 }
1653
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001654 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001655 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1656 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001657 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001658 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001659
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001660 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001661 read_buff_read = 0;
1662 read_buff_size = pipe_buff_size + 1;
1663 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001664
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001665 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001666 read_buff_read += bytesread;
1667 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001668 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001669 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001670
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001671 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001672
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001673 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001674 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001675
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001676 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001677 read_buff_word = read_buff_ptr = read_buff;
1678
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001679 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001680
1681 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001682 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001683 if (read_buff_word != read_buff_ptr) {
1684 if (!do_int_spell_fix(read_buff_word)) {
1685 read_buff_word = read_buff_ptr;
1686 break;
1687 }
1688 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001689 read_buff_word = read_buff_ptr + 1;
1690 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001691 read_buff_ptr++;
1692 }
1693
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001694 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001695 if (read_buff_word != read_buff_ptr)
1696 do_int_spell_fix(read_buff_word);
1697
Chris Allegretta271e9722000-11-10 18:15:43 +00001698 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001699 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001700 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001701
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001702 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001703 waitpid(pid_spell, &spell_status, 0);
1704 waitpid(pid_sort, &sort_status, 0);
1705 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001706
Chris Allegretta334a9402002-12-16 04:25:53 +00001707 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1708 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001709
Chris Allegretta334a9402002-12-16 04:25:53 +00001710 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1711 return _("Error invoking \"sort -f\"");
1712
1713 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1714 return _("Error invoking \"uniq\"");
1715
1716 /* Otherwise... */
1717 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001718
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001719 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001720
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001721 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001722 close(tempfile_fd);
1723 close(spell_fd[0]);
1724 close(spell_fd[1]);
1725 close(sort_fd[0]);
1726 close(sort_fd[1]);
1727 close(uniq_fd[0]);
1728 close(uniq_fd[1]);
1729 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001730}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001731
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001732/* External spell checking. Return value: NULL for normal termination,
1733 * otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001734const char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001735{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001736 int alt_spell_status, lineno_cur = current->lineno;
1737 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001738 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001739 char *ptr;
1740 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001741 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001742#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001743 int mark_set = ISSET(MARK_ISSET);
1744 int mbb_lineno_cur = 0;
1745 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001746 * the alternate spell command. The line that mark_beginbuf
1747 * points to will be freed, so we save the line number and
1748 * restore afterwards. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001749
1750 if (mark_set) {
1751 mbb_lineno_cur = mark_beginbuf->lineno;
1752 UNSET(MARK_ISSET);
1753 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001754#endif
1755
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001756 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001757
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001758 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001759 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001760 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001761
Chris Allegrettae434b452001-01-27 19:25:00 +00001762 spellargs[0] = strtok(alt_speller, " ");
1763 while ((ptr = strtok(NULL, " ")) != NULL) {
1764 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001765 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001766 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001767 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001768 spellargs[arglen - 1] = NULL;
1769 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001770 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001771
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001772 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001773 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001774 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00001775 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001776
1777 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001778 exit(1);
1779 }
1780
1781 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001782 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001783 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001784
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001785 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001786 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001787
Chris Allegretta334a9402002-12-16 04:25:53 +00001788 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1789 char *altspell_error = NULL;
1790 char *invoke_error = _("Could not invoke \"%s\"");
1791 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1792
1793 altspell_error = charalloc(msglen);
1794 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1795 return altspell_error;
1796 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001797
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001798 refresh();
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001799#ifndef NANO_SMALL
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001800 if (!mark_set) {
1801 /* Only reload the temp file if it isn't a marked selection. */
1802#endif
1803 free_filestruct(fileage);
1804 global_init(1);
1805 open_file(tempfile_name, 0, 1);
1806#ifndef NANO_SMALL
1807 }
1808
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001809 if (mark_set) {
1810 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1811 mark_beginbuf = current;
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001812 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001813 mark_beginx = current_x;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001814 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001815 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001816#endif
1817
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001818 /* Go back to the old position, mark the file as modified, and make
1819 * sure that the titlebar is refreshed. */
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001820 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001821 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001822 clearok(topwin, FALSE);
1823 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001824
Chris Allegretta334a9402002-12-16 04:25:53 +00001825 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001826}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001827
1828int do_spell(void)
1829{
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001830 int i;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001831 char *temp = safe_tempnam(0, "nano.");
1832 const char *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001833
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001834 if (temp == NULL) {
1835 statusbar(_("Could not create temp file: %s"), strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001836 return 0;
1837 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001838
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001839#ifndef NANO_SMALL
1840 if (ISSET(MARK_ISSET))
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001841 i = write_marked(temp, TRUE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001842 else
1843#endif
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001844 i = write_file(temp, TRUE, FALSE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001845
1846 if (i == -1) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001847 statusbar(_("Unable to write temp file: %s"), strerror(errno));
Chris Allegrettabef12972002-03-06 03:30:40 +00001848 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001849 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001850 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001851
Chris Allegrettae1f14522001-09-19 03:19:43 +00001852#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001853 /* Update the current open_files entry before spell-checking, in
1854 * case any problems occur. */
Chris Allegretta48b06702002-02-22 04:30:50 +00001855 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001856#endif
1857
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001858 spell_msg = alt_speller != NULL ? do_alt_speller(temp) :
1859 do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001860 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001861 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001862
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001863 if (spell_msg != NULL) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001864 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
1865 strerror(errno));
Chris Allegretta334a9402002-12-16 04:25:53 +00001866 return 0;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001867 } else
1868 statusbar(_("Finished checking spelling"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001869
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001870 return 1;
Chris Allegretta67105eb2000-07-03 03:18:32 +00001871}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001872#endif /* !DISABLE_SPELLER */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001873
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001874#if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001875/* The "indentation" of a line is the white-space between the quote part
1876 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001877size_t indent_length(const char *line)
1878{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001879 size_t len = 0;
1880
1881 assert(line != NULL);
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001882 while (isblank(*line)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001883 line++;
1884 len++;
1885 }
1886 return len;
1887}
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001888#endif /* !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001889
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001890#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001891/* justify_format() replaces Tab by Space and multiple spaces by 1
1892 * (except it maintains 2 after a . ! or ?). Note the terminating \0
Chris Allegretta6df90f52002-07-19 01:08:59 +00001893 * counts as a space.
1894 *
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001895 * justify_format() might make line->data shorter, and change the actual
1896 * pointer with null_at().
Chris Allegretta6df90f52002-07-19 01:08:59 +00001897 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001898 * justify_format() will not look at the first skip characters of line.
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001899 * skip should be at most strlen(line->data). The character at
1900 * line[skip + 1] must not be whitespace. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001901void justify_format(filestruct *line, size_t skip)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001902{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001903 const char *punct = ".?!";
1904 const char *brackets = "'\")}]>";
Chris Allegretta6df90f52002-07-19 01:08:59 +00001905 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001906
Chris Allegretta6df90f52002-07-19 01:08:59 +00001907 /* These four asserts are assumptions about the input data. */
1908 assert(line != NULL);
1909 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001910 assert(skip < strlen(line->data));
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001911 assert(!isblank(line->data[skip]));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001912
Chris Allegretta6df90f52002-07-19 01:08:59 +00001913 back = line->data + skip;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001914 for (front = back; ; front++) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001915 int remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001916 /* Do we want to remove this space? */
1917
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001918 if (*front == '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001919 *front = ' ';
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001920
David Lawrence Ramsey021960d2004-05-13 23:19:01 +00001921 /* These tests are safe since line->data + skip is not a
1922 * space. */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001923 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001924 const char *bob = front - 2;
1925
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001926 remove_space = TRUE;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001927 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001928 if (strchr(punct, *bob) != NULL) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001929 remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001930 break;
1931 }
1932 if (strchr(brackets, *bob) == NULL)
1933 break;
1934 }
1935 }
1936
1937 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001938 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001939 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001940#ifndef NANO_SMALL
1941 if (mark_beginbuf == line && back - line->data < mark_beginx)
1942 mark_beginx--;
1943#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001944 if (*front == '\0')
1945 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00001946 } else {
1947 *back = *front;
1948 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001949 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001950 if (*front == '\0')
1951 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001952 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001953
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001954 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00001955 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00001956
Chris Allegretta6df90f52002-07-19 01:08:59 +00001957 /* Now back is the new end of line->data. */
1958 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00001959 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001960 null_at(&line->data, back - line->data);
1961#ifndef NANO_SMALL
1962 if (mark_beginbuf == line && back - line->data < mark_beginx)
1963 mark_beginx = back - line->data;
1964#endif
1965 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001966}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001967
1968/* The "quote part" of a line is the largest initial substring matching
1969 * the quote string. This function returns the length of the quote part
1970 * of the given line.
1971 *
1972 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1973 * quotestr. */
1974#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001975size_t quote_length(const char *line, const regex_t *qreg)
1976{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001977 regmatch_t matches;
1978 int rc = regexec(qreg, line, 1, &matches, 0);
1979
1980 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
1981 return 0;
1982 /* matches.rm_so should be 0, since the quote string should start with
1983 * the caret ^. */
1984 return matches.rm_eo;
1985}
1986#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001987size_t quote_length(const char *line)
1988{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001989 size_t qdepth = 0;
1990 size_t qlen = strlen(quotestr);
1991
1992 /* Compute quote depth level */
1993 while (!strcmp(line + qdepth, quotestr))
1994 qdepth += qlen;
1995 return qdepth;
1996}
1997#endif /* !HAVE_REGEX_H */
1998
Chris Allegretta6df90f52002-07-19 01:08:59 +00001999/* a_line and b_line are lines of text. The quotation part of a_line is
2000 * the first a_quote characters. Check that the quotation part of
2001 * b_line is the same. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002002int quotes_match(const char *a_line, size_t a_quote, IFREG(const char
2003 *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002004{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002005 /* Here is the assumption about a_quote: */
2006 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00002007 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00002008 !strncmp(a_line, b_line, a_quote);
2009}
2010
2011/* We assume a_line and b_line have no quote part. Then, we return whether
2012 * b_line could follow a_line in a paragraph. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002013size_t indents_match(const char *a_line, size_t a_indent, const char
2014 *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002015{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002016 assert(a_indent == indent_length(a_line));
2017 assert(b_indent == indent_length(b_line));
2018
2019 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2020}
2021
2022/* Put the next par_len lines, starting with first_line, in the cut
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002023 * buffer, not allowing them to be concatenated. We assume there are
2024 * enough lines after first_line. We leave copies of the lines in
2025 * place, too. We return the new copy of first_line. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002026filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t
2027 quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002028{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002029 /* We put the original lines, not copies, into the cutbuffer, just
2030 * out of a misguided sense of consistency, so if you uncut, you get
2031 * the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002032 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002033
2034 set_modified();
2035 cutbuffer = NULL;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002036 for (; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002037 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002038
Chris Allegretta908f7702003-01-15 11:18:58 +00002039 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002040 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002041 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002042 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002043 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002044 edittop = bob;
2045#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002046 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002047 mark_beginbuf = bob;
2048#endif
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002049 justify_format(bob, quote_len + indent_length(bob->data + quote_len));
Chris Allegretta6df90f52002-07-19 01:08:59 +00002050
Chris Allegretta908f7702003-01-15 11:18:58 +00002051 assert(alice != NULL && bob != NULL);
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002052 add_to_cutbuffer(alice, FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002053 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002054 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002055 }
2056 return first_line;
2057}
2058
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002059/* Is it possible to break line at or before goal? */
2060int breakable(const char *line, int goal)
2061{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002062 for (; *line != '\0' && goal >= 0; line++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002063 if (isblank(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002064 return TRUE;
2065
2066 if (is_cntrl_char(*line) != 0)
2067 goal -= 2;
2068 else
2069 goal -= 1;
2070 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002071 /* If goal is not negative, the whole line (one word) was short
2072 * enough. */
2073 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002074}
2075
Chris Allegretta6df90f52002-07-19 01:08:59 +00002076/* We are trying to break a chunk off line. We find the last space such
2077 * that the display length to there is at most goal + 1. If there is
2078 * no such space, and force is not 0, then we find the first space.
2079 * Anyway, we then take the last space in that group of spaces. The
2080 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002081int break_line(const char *line, int goal, int force)
2082{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002083 /* Note that we use int instead of size_t, since goal is at most COLS,
2084 * the screen width, which will always be reasonably small. */
2085 int space_loc = -1;
2086 /* Current tentative return value. Index of the last space we
2087 * found with short enough display width. */
2088 int cur_loc = 0;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002089 /* Current index in line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002090
2091 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002092 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002093 if (*line == ' ')
2094 space_loc = cur_loc;
2095 assert(*line != '\t');
2096
Chris Allegrettacf287c82002-07-20 13:57:41 +00002097 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002098 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002099 else
2100 goal--;
2101 }
2102 if (goal >= 0)
2103 /* In fact, the whole line displays shorter than goal. */
2104 return cur_loc;
2105 if (space_loc == -1) {
2106 /* No space found short enough. */
2107 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002108 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002109 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002110 return cur_loc;
2111 return -1;
2112 }
2113 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002114 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002115 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2116 *(line - cur_loc + space_loc + 1) == '\0')
2117 space_loc++;
2118 return space_loc;
2119}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002120
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002121/* Search a paragraph. If search_type is JUSTIFY, search for the
2122 * beginning of the current paragraph or, if we're at the end of it, the
2123 * beginning of the next paragraph. If search_type is BEGIN, search for
2124 * the beginning of the current paragraph or, if we're already there,
2125 * the beginning of the previous paragraph. If search_type is END,
2126 * search for the end of the current paragraph or, if we're already
2127 * there, the end of the next paragraph. Afterwards, save the quote
2128 * length, paragraph length, and indentation length in *quote, *par, and
2129 * *indent if they aren't NULL, and refresh the screen if do_refresh is
2130 * TRUE. Return 0 if we found a paragraph, or 1 if there was an error
2131 * or we didn't find a paragraph.
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002132 *
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002133 * To explain the searching algorithm, I first need to define some
Chris Allegretta6df90f52002-07-19 01:08:59 +00002134 * phrases about paragraphs and quotation:
2135 * A line of text consists of a "quote part", followed by an
2136 * "indentation part", followed by text. The functions quote_length()
2137 * and indent_length() calculate these parts.
2138 *
2139 * A line is "part of a paragraph" if it has a part not in the quote
2140 * part or the indentation.
2141 *
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002142 * A line is "the beginning of a paragraph" if it is part of a
2143 * paragraph and
Chris Allegretta6df90f52002-07-19 01:08:59 +00002144 * 1) it is the top line of the file, or
2145 * 2) the line above it is not part of a paragraph, or
2146 * 3) the line above it does not have precisely the same quote
2147 * part, or
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002148 * 4) the indentation of this line is not an initial substring of
2149 * the indentation of the previous line, or
Chris Allegretta6df90f52002-07-19 01:08:59 +00002150 * 5) this line has no quote part and some indentation, and
2151 * AUTOINDENT is not set.
2152 * The reason for number 5) is that if AUTOINDENT is not set, then an
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002153 * indented line is expected to start a paragraph, like in books.
2154 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2155 * turned on.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002156 *
2157 * A contiguous set of lines is a "paragraph" if each line is part of
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002158 * a paragraph and only the first line is the beginning of a
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002159 * paragraph. */
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002160int do_para_search(justbegend search_type, size_t *quote, size_t *par,
2161 size_t *indent, int do_refresh)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002162{
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002163 const filestruct *current_save = current;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002164 size_t quote_len;
2165 /* Length of the initial quotation of the paragraph we
2166 * search. */
2167 size_t par_len;
2168 /* Number of lines in that paragraph. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002169 size_t indent_len;
2170 /* Generic indentation length. */
2171 filestruct *line;
2172 /* Generic line of text. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002173 static int do_restart = 1;
2174 /* Whether we're restarting when searching for the beginning
2175 * line of the paragraph. */
2176
2177#ifdef HAVE_REGEX_H
2178 regex_t qreg; /* qreg is the compiled quotation regexp. We no
2179 * longer care about quotestr. */
2180 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2181
2182 if (rc != 0) {
2183 size_t size = regerror(rc, &qreg, NULL, 0);
2184 char *strerror = charalloc(size);
2185
2186 regerror(rc, &qreg, strerror, size);
2187 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2188 free(strerror);
2189 return 1;
2190 }
2191#endif
2192
2193 /* Here is an assumption that is always true anyway. */
2194 assert(current != NULL);
2195
2196 current_x = 0;
2197
2198 restart_para_search:
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002199 /* Here we find the first line of the paragraph to search. If the
2200 * current line is in a paragraph, then we move back to the first
2201 * line. Otherwise, we move to the first line that is in a
2202 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002203 quote_len = quote_length(IFREG(current->data, &qreg));
2204 indent_len = indent_length(current->data + quote_len);
2205
2206 if (current->data[quote_len + indent_len] != '\0') {
2207 /* This line is part of a paragraph. So we must search back to
2208 * the first line of this paragraph. First we check items 1)
2209 * and 3) above. */
2210 while (current->prev != NULL && quotes_match(current->data,
2211 quote_len, IFREG(current->prev->data, &qreg))) {
2212 size_t temp_id_len =
2213 indent_length(current->prev->data + quote_len);
2214 /* The indentation length of the previous line. */
2215
2216 /* Is this line the beginning of a paragraph, according to
2217 * items 2), 5), or 4) above? If so, stop. */
2218 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002219 (quote_len == 0 && indent_len > 0
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002220#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002221 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002222#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002223 ) || !indents_match(current->prev->data + quote_len,
2224 temp_id_len, current->data + quote_len, indent_len))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002225 break;
2226 indent_len = temp_id_len;
2227 current = current->prev;
2228 current_y--;
2229 }
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002230 } else if (search_type == BEGIN) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002231 /* This line is not part of a paragraph. Move up until we get
2232 * to a non "blank" line, and then move down once. */
2233 do {
2234 /* There is no previous paragraph, so nothing to move to. */
2235 if (current->prev == NULL) {
2236 placewewant = 0;
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002237 if (do_refresh)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002238 edit_redraw(current_save);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002239#ifdef HAVE_REGEX_H
2240 if (!do_restart)
2241 regfree(&qreg);
2242#endif
2243 return 1;
2244 }
2245 current = current->prev;
2246 current_y--;
2247 quote_len = quote_length(IFREG(current->data, &qreg));
2248 indent_len = indent_length(current->data + quote_len);
2249 } while (current->data[quote_len + indent_len] == '\0');
2250 current = current->next;
2251 } else {
2252 /* This line is not part of a paragraph. Move down until we get
2253 * to a non "blank" line. */
2254 do {
2255 /* There is no next paragraph, so nothing to move to. */
2256 if (current->next == NULL) {
2257 placewewant = 0;
2258 if (do_refresh)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002259 edit_redraw(current_save);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002260#ifdef HAVE_REGEX_H
2261 regfree(&qreg);
2262#endif
2263 return 1;
2264 }
2265 current = current->next;
2266 current_y++;
2267 quote_len = quote_length(IFREG(current->data, &qreg));
2268 indent_len = indent_length(current->data + quote_len);
2269 } while (current->data[quote_len + indent_len] == '\0');
2270 }
2271
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002272 /* Now current is the first line of the paragraph, and quote_len is
2273 * the quotation length of that line. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002274
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002275 /* Next step, compute par_len, the number of lines in this
2276 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002277 line = current;
2278 par_len = 1;
2279 indent_len = indent_length(line->data + quote_len);
2280
2281 while (line->next != NULL && quotes_match(current->data, quote_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002282 IFREG(line->next->data, &qreg))) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002283 size_t temp_id_len = indent_length(line->next->data + quote_len);
2284
2285 if (!indents_match(line->data + quote_len, indent_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002286 line->next->data + quote_len, temp_id_len) ||
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002287 line->next->data[quote_len + temp_id_len] == '\0' ||
2288 (quote_len == 0 && temp_id_len > 0
2289#ifndef NANO_SMALL
2290 && !ISSET(AUTOINDENT)
2291#endif
2292 ))
2293 break;
2294 indent_len = temp_id_len;
2295 line = line->next;
2296 par_len++;
2297 }
2298
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002299 if (search_type == BEGIN) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002300 /* We're on the same line we started on. Move up until we get
2301 * to a non-"blank" line, restart the search from there until we
2302 * find a line that's part of a paragraph, and search once more
2303 * so that we end up at the beginning of that paragraph. */
2304 if (current != fileage && current == current_save && do_restart) {
2305 while (current->prev != NULL) {
2306 size_t i, j = 0;
2307 current = current->prev;
2308 current_y--;
2309 /* Skip over lines consisting only of spacing
2310 * characters, as searching for the end of the paragraph
2311 * does. */
2312 for (i = 0; current->data[i] != '\0'; i++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002313 if (isblank(current->data[i]))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002314 j++;
2315 else {
2316 i = 0;
2317 j = 1;
2318 break;
2319 }
2320 }
2321 if (i != j && strlen(current->data) >=
2322 (quote_len + indent_len) &&
2323 current->data[quote_len + indent_len] != '\0') {
2324 do_restart = 0;
2325 break;
2326 }
2327 }
2328 goto restart_para_search;
2329 } else
2330 do_restart = 1;
2331 }
2332
2333#ifdef HAVE_REGEX_H
2334 /* We no longer need to check quotation. */
2335 regfree(&qreg);
2336#endif
2337
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002338 /* Now par_len is the number of lines in this paragraph. We should
2339 * never call quotes_match() or quote_length() again. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002340
2341 /* If we're searching for the end of the paragraph, move down the
2342 * number of lines in the paragraph. */
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002343 if (search_type == END) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002344 for (; par_len > 0; current_y++, par_len--)
2345 current = current->next;
2346 }
2347
2348 /* Refresh the screen if needed. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002349 if (do_refresh)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002350 edit_redraw(current_save);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002351
2352 /* Save the values of quote_len, par_len, and indent_len if
2353 * needed. */
2354 if (quote != NULL)
2355 *quote = quote_len;
2356 if (par != NULL)
2357 *par = par_len;
2358 if (indent != NULL)
2359 *indent = indent_len;
2360
2361 return 0;
2362}
2363
2364int do_para_begin(void)
2365{
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002366 return do_para_search(BEGIN, NULL, NULL, NULL, TRUE);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002367}
2368
2369int do_para_end(void)
2370{
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002371 return do_para_search(END, NULL, NULL, NULL, TRUE);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002372}
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002373
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002374/* If full_justify is TRUE, justify the entire file. Otherwise, justify
2375 * the current paragraph. */
2376int do_justify(int full_justify)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002377{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002378 size_t quote_len;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002379 /* Length of the initial quotation of the paragraph we
2380 * justify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002381 size_t par_len;
2382 /* Number of lines in that paragraph. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002383 filestruct *first_par_line = NULL;
2384 /* Will be the first line of the resulting justified paragraph.
2385 * For restoring after uncut. */
David Lawrence Ramsey36e363f2004-05-17 20:38:00 +00002386 filestruct *last_par_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002387 /* Will be the last line of the result, also for uncut. */
2388 filestruct *cutbuffer_save = cutbuffer;
2389 /* When the paragraph gets modified, all lines from the changed
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002390 * one down are stored in the cutbuffer. We back up the
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002391 * original to restore it later. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002392
2393 /* We save these global variables to be restored if the user
2394 * unjustifies. Note we don't need to save totlines. */
2395 int current_x_save = current_x;
2396 int current_y_save = current_y;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002397 int flags_save = flags;
2398 long totsize_save = totsize;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002399 filestruct *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002400 filestruct *edittop_save = edittop;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002401#ifndef NANO_SMALL
2402 filestruct *mark_beginbuf_save = mark_beginbuf;
2403 int mark_beginx_save = mark_beginx;
2404#endif
2405
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002406 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002407 size_t i; /* Generic loop variable. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002408
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002409 /* If we're justifying the entire file, start at the beginning. */
2410 if (full_justify)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002411 current = fileage;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002412
2413 last_par_line = current;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002414
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002415 while (TRUE) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002416
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002417 /* First, search for the beginning of the current paragraph or,
2418 * if we're at the end of it, the beginning of the next
2419 * paragraph. Save the quote length, paragraph length, and
2420 * indentation length and don't refresh the screen yet (since
2421 * we'll do that after we justify). If the search failed and
2422 * we're justifying the whole file, move the last line of the
2423 * text we're justifying to just before the magicline, which is
2424 * where it'll be anyway if we've searched the entire file, and
2425 * break out of the loop; otherwise, refresh the screen and get
2426 * out. */
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002427 if (do_para_search(JUSTIFY, &quote_len, &par_len, &indent_len,
2428 FALSE) != 0) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002429 if (full_justify) {
2430 /* This should be safe in the event of filebot->prev's
2431 * being NULL, since only last_par_line->next is used if
2432 * we eventually unjustify. */
2433 last_par_line = filebot->prev;
2434 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002435 } else {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002436 edit_refresh();
2437 return 0;
2438 }
2439 }
2440
2441 /* Next step, we loop through the lines of this paragraph,
2442 * justifying each one individually. */
2443 for (; par_len > 0; current_y++, par_len--) {
2444 size_t line_len;
2445 size_t display_len;
2446 /* The width of current in screen columns. */
2447 int break_pos;
2448 /* Where we will break the line. */
2449
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002450 indent_len = quote_len + indent_length(current->data +
2451 quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002452
2453 /* justify_format() removes excess spaces from the line, and
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002454 * changes tabs to spaces. After calling it, we call
2455 * backup_lines(), which copies the original paragraph to
2456 * the cutbuffer for unjustification and then calls
2457 * justify_format() on the remaining lines. */
2458 justify_format(current, indent_len);
2459 if (first_par_line == NULL)
2460 first_par_line = backup_lines(current, full_justify ?
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002461 filebot->lineno - current->lineno : par_len, quote_len);
2462
2463 line_len = strlen(current->data);
2464 display_len = strlenpt(current->data);
2465
2466 if (display_len > fill) {
2467 /* The line is too long. Try to wrap it to the next. */
2468 break_pos = break_line(current->data + indent_len,
2469 fill - strnlenpt(current->data, indent_len), TRUE);
2470 if (break_pos == -1 || break_pos + indent_len == line_len)
2471 /* We can't break the line, or don't need to, so
2472 * just go on to the next. */
2473 goto continue_loc;
2474 break_pos += indent_len;
2475 assert(break_pos < line_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002476 if (par_len == 1) {
2477 /* There is no next line in this paragraph. We make
2478 * a new line and copy text after break_pos into
2479 * it. */
2480 splice_node(current, make_new_node(current), current->next);
2481 /* In a non-quoted paragraph, we copy the indent
2482 * only if AUTOINDENT is turned on. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002483 if (quote_len == 0
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002484#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002485 && !ISSET(AUTOINDENT)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002486#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002487 )
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002488 indent_len = 0;
2489 current->next->data = charalloc(indent_len + line_len -
2490 break_pos);
2491 strncpy(current->next->data, current->data, indent_len);
2492 strcpy(current->next->data + indent_len,
2493 current->data + break_pos + 1);
2494 assert(strlen(current->next->data) ==
2495 indent_len + line_len - break_pos - 1);
2496 totlines++;
2497 totsize += indent_len;
2498 par_len++;
2499 } else {
2500 size_t next_line_len = strlen(current->next->data);
2501
2502 indent_len = quote_len +
2503 indent_length(current->next->data + quote_len);
2504 current->next->data = charealloc(current->next->data,
2505 next_line_len + line_len - break_pos + 1);
2506
2507 charmove(current->next->data + indent_len + line_len -
2508 break_pos, current->next->data + indent_len,
2509 next_line_len - indent_len + 1);
2510 strcpy(current->next->data + indent_len,
2511 current->data + break_pos + 1);
2512 current->next->data[indent_len + line_len - break_pos - 1]
2513 = ' ';
2514#ifndef NANO_SMALL
2515 if (mark_beginbuf == current->next) {
2516 if (mark_beginx < indent_len)
2517 mark_beginx = indent_len;
2518 mark_beginx += line_len - break_pos;
2519 }
2520#endif
2521 }
2522#ifndef NANO_SMALL
2523 if (mark_beginbuf == current && mark_beginx > break_pos) {
2524 mark_beginbuf = current->next;
2525 mark_beginx -= break_pos + 1 - indent_len;
2526 }
2527#endif
2528 null_at(&current->data, break_pos);
2529 current = current->next;
2530 } else if (display_len < fill && par_len > 1) {
2531 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002532
2533 indent_len = quote_len +
2534 indent_length(current->next->data + quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002535 /* If we can't pull a word from the next line up to this
2536 * one, just go on. */
2537 if (!breakable(current->next->data + indent_len,
2538 fill - display_len - 1))
2539 goto continue_loc;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002540
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002541 break_pos = break_line(current->next->data + indent_len,
2542 fill - display_len - 1, FALSE);
2543 assert(break_pos != -1);
2544
2545 current->data = charealloc(current->data,
2546 line_len + break_pos + 2);
2547 current->data[line_len] = ' ';
2548 strncpy(current->data + line_len + 1,
2549 current->next->data + indent_len, break_pos);
2550 current->data[line_len + break_pos + 1] = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002551#ifndef NANO_SMALL
2552 if (mark_beginbuf == current->next) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002553 if (mark_beginx < indent_len + break_pos) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002554 mark_beginbuf = current;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002555 if (mark_beginx <= indent_len)
2556 mark_beginx = line_len + 1;
2557 else
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002558 mark_beginx = line_len + 1 + mark_beginx -
2559 indent_len;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002560 } else
2561 mark_beginx -= break_pos + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002562 }
2563#endif
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002564 next_line_len = strlen(current->next->data);
2565 if (indent_len + break_pos == next_line_len) {
2566 filestruct *line = current->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002567
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002568 /* Don't destroy edittop! */
2569 if (line == edittop)
2570 edittop = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002571
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002572 unlink_node(line);
2573 delete_node(line);
2574 totlines--;
2575 totsize -= indent_len;
2576 current_y--;
2577 } else {
2578 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002579 current->next->data + indent_len + break_pos + 1,
2580 next_line_len - break_pos - indent_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002581 null_at(&current->next->data, next_line_len - break_pos);
2582 current = current->next;
2583 }
2584 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002585 continue_loc:
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002586 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002587 current = current->next;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002588
2589 /* If the line we were on before still exists, and it was
2590 * not the last line of the paragraph, add a space to the
David Lawrence Ramsey684e7eb2004-05-20 14:31:15 +00002591 * end of it to replace the one removed or left out by
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002592 * justify_format(). */
2593 if (current->prev != NULL && par_len > 1) {
2594 size_t prev_line_len = strlen(current->prev->data);
2595 current->prev->data = charealloc(current->prev->data,
2596 prev_line_len + 2);
2597 current->prev->data[prev_line_len] = ' ';
2598 current->prev->data[prev_line_len + 1] = '\0';
2599 totsize++;
2600 }
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002601 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002602
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002603 /* We've just justified a paragraph. If we're not justifying the
2604 * entire file, break out of the loop. Otherwise, continue the
2605 * loop so that we justify all the paragraphs in the file. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002606 if (!full_justify)
2607 break;
2608
2609 } /* while (TRUE) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002610
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002611 /* We are now done justifying the paragraph or the file, so clean
2612 * up. totlines, totsize, and current_y have been maintained above.
2613 * Set last_par_line to the new end of the paragraph, update
2614 * fileage, and set current_x. Also, edit_refresh() needs the line
2615 * numbers to be right, so renumber(). */
2616 last_par_line = current->prev;
2617 if (first_par_line->prev == NULL)
2618 fileage = first_par_line;
2619 renumber(first_par_line);
2620
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002621 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002622
Chris Allegretta9149e612000-11-27 00:23:41 +00002623 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002624 /* Display the shortcut list with UnJustify. */
Chris Allegretta07798352000-11-27 22:58:23 +00002625 shortcut_init(1);
2626 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002627 reset_cursor();
2628
Chris Allegretta6df90f52002-07-19 01:08:59 +00002629 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002630 * keystroke and return. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002631 {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002632 int meta_key;
2633 i = get_kbinput(edit, &meta_key);
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002634#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002635 /* If it was a mouse click, parse it with do_mouse() and it
2636 * might become the unjustify key. Else give it back to the
2637 * input stream. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002638 if (i == KEY_MOUSE) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002639 do_mouse();
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002640 i = get_kbinput(edit, &meta_key);
2641 }
Chris Allegretta5f071802001-05-06 02:34:31 +00002642#endif
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002643 }
Chris Allegretta5f071802001-05-06 02:34:31 +00002644
David Lawrence Ramseyc91696e2004-01-29 04:16:23 +00002645 if (i != NANO_UNJUSTIFY_KEY && i != NANO_UNJUSTIFY_FKEY) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002646 ungetch(i);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002647 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002648 } else {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002649 /* Else restore the justify we just did (ungrateful user!). */
2650 filestruct *cutbottom = get_cutbottom();
2651
Chris Allegretta6df90f52002-07-19 01:08:59 +00002652 current = current_save;
2653 current_x = current_x_save;
2654 current_y = current_y_save;
2655 edittop = edittop_save;
Chris Allegrettad022eac2000-11-27 02:50:49 +00002656
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002657 /* Splice the cutbuffer back into the file. */
2658 cutbottom->next = last_par_line->next;
2659 cutbottom->next->prev = cutbottom;
2660 /* The line numbers after the end of the paragraph have been
2661 * changed, so we change them back. */
2662 renumber(cutbottom->next);
2663 if (first_par_line->prev != NULL) {
2664 cutbuffer->prev = first_par_line->prev;
2665 cutbuffer->prev->next = cutbuffer;
2666 } else
2667 fileage = cutbuffer;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002668
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002669 last_par_line->next = NULL;
2670 free_filestruct(first_par_line);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002671
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002672 /* Restore global variables from before the justify. */
2673 totsize = totsize_save;
2674 totlines = filebot->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002675#ifndef NANO_SMALL
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002676 mark_beginbuf = mark_beginbuf_save;
2677 mark_beginx = mark_beginx_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002678#endif
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002679 flags = flags_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002680 if (!ISSET(MODIFIED))
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002681 titlebar(NULL);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002682 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002683 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002684 cutbuffer = cutbuffer_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002685 /* Note that now cutbottom is invalid, but that's okay. */
2686 blank_statusbar();
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002687 /* Display the shortcut list with UnCut. */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002688 shortcut_init(0);
2689 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002690
Chris Allegretta6df90f52002-07-19 01:08:59 +00002691 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002692}
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002693
2694int do_justify_void(void)
2695{
2696 return do_justify(FALSE);
2697}
2698
2699int do_full_justify(void)
2700{
2701 return do_justify(TRUE);
2702}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00002703#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002704
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002705int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002706{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002707 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002708
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002709 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002710
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002711#ifdef ENABLE_MULTIBUFFER
2712 if (!close_open_file()) {
2713 display_main_list();
2714 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002715 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002716 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002717#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002718 finish();
Chris Allegretta756f2202000-09-01 13:32:47 +00002719 }
2720
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002721 if (ISSET(TEMP_OPT))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002722 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002723 else
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002724 i = do_yesno(FALSE, _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002725
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002726#ifdef DEBUG
2727 dump_buffer(fileage);
2728#endif
2729
2730 if (i == 1) {
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002731 if (do_writeout(TRUE) > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002732
2733#ifdef ENABLE_MULTIBUFFER
2734 if (!close_open_file()) {
2735 display_main_list();
2736 return 1;
2737 }
2738 else
2739#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002740 finish();
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002741 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002742 } else if (i == 0) {
2743
2744#ifdef ENABLE_MULTIBUFFER
2745 if (!close_open_file()) {
2746 display_main_list();
2747 return 1;
2748 }
2749 else
2750#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002751 finish();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002752 } else
2753 statusbar(_("Cancelled"));
2754
2755 display_main_list();
2756 return 1;
2757}
2758
2759void signal_init(void)
2760{
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002761 /* Trap SIGINT and SIGQUIT because we want them to do useful
2762 * things. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002763 memset(&act, 0, sizeof(struct sigaction));
2764 act.sa_handler = SIG_IGN;
2765 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00002766 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002767
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002768 /* Trap SIGHUP and SIGTERM because we want to write the file out. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002769 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002770 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002771 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002772
2773#ifndef NANO_SMALL
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002774 /* Trap SIGWINCH because we want to handle window resizes. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002775 act.sa_handler = handle_sigwinch;
2776 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002777 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002778#endif
2779
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002780 /* Trap normal suspend (^Z) so we can handle it ourselves. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002781 if (!ISSET(SUSPEND)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002782 act.sa_handler = SIG_IGN;
2783 sigaction(SIGTSTP, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002784 } else {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002785 /* Block all other signals in the suspend and continue handlers.
2786 * If we don't do this, other stuff interrupts them! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002787 sigfillset(&act.sa_mask);
2788
2789 act.sa_handler = do_suspend;
2790 sigaction(SIGTSTP, &act, NULL);
2791
2792 act.sa_handler = do_cont;
2793 sigaction(SIGCONT, &act, NULL);
2794 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002795}
2796
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002797/* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002798RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002799{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002800 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002801}
2802
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002803/* Handler for SIGTSTP (suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002804RETSIGTYPE do_suspend(int signal)
2805{
2806 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002807 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002808 fflush(stdout);
2809
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002810 /* Restore the old terminal settings. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002811 tcsetattr(0, TCSANOW, &oldterm);
2812
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002813 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002814 * suspended. */
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002815 act.sa_handler = handle_hupterm;
2816 sigaction(SIGHUP, &act, NULL);
2817 sigaction(SIGTERM, &act, NULL);
2818
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002819 /* Do what mutt does: send ourselves a SIGSTOP. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002820 kill(0, SIGSTOP);
2821}
2822
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002823/* Handler for SIGCONT (continue after suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002824RETSIGTYPE do_cont(int signal)
2825{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002826#ifndef NANO_SMALL
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002827 /* Perhaps the user resized the window while we slept. Handle it
2828 * and update the screen in the process. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002829 handle_sigwinch(0);
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002830#else
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002831 /* Just update the screen. */
2832 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002833#endif
2834}
2835
2836#ifndef NANO_SMALL
2837void handle_sigwinch(int s)
2838{
2839 const char *tty = ttyname(0);
2840 int fd;
2841 int result = 0;
2842 struct winsize win;
2843
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002844 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002845 return;
2846 fd = open(tty, O_RDWR);
2847 if (fd == -1)
2848 return;
2849 result = ioctl(fd, TIOCGWINSZ, &win);
2850 close(fd);
2851 if (result == -1)
2852 return;
2853
2854 /* Could check whether the COLS or LINES changed, and return
2855 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2856 * variables, and in some cases ncurses has already updated them.
2857 * But not in all cases, argh. */
2858 COLS = win.ws_col;
2859 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002860 editwinrows = LINES - 5 + no_help();
2861 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002862 die_too_small();
2863
2864#ifndef DISABLE_WRAPJUSTIFY
2865 fill = wrap_at;
2866 if (fill <= 0)
2867 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002868 if (fill < 0)
2869 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002870#endif
2871
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002872 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002873 memset(hblank, ' ', COLS);
2874 hblank[COLS] = '\0';
2875
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002876#ifdef USE_SLANG
2877 /* Slang curses emulation brain damage, part 1: If we just do what
2878 * curses does here, it'll only work properly if the resize made the
2879 * window smaller. Do what mutt does: Leave and immediately reenter
2880 * Slang screen management mode. */
2881 SLsmg_reset_smg();
2882 SLsmg_init_smg();
2883#else
2884 /* Do the equivalent of what Minimum Profit does: Leave and
2885 * immediately reenter curses mode. */
2886 endwin();
2887 refresh();
2888#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002889
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002890 /* Do the equivalent of what both mutt and Minimum Profit do:
2891 * Reinitialize all the windows based on the new screen
2892 * dimensions. */
2893 window_init();
2894
2895 /* Redraw the contents of the windows that need it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002896 blank_statusbar();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002897 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002898 total_refresh();
2899
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002900 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002901 curs_set(1);
2902
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002903 /* Restore the terminal to its previously saved state. */
2904 resetty();
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002905
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00002906 /* Reset all the input routines that rely on character sequences. */
2907 reset_kbinput();
2908
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002909 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002910 siglongjmp(jmpbuf, 1);
2911}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002912
2913void allow_pending_sigwinch(int allow)
2914{
2915 sigset_t winch;
2916 sigemptyset(&winch);
2917 sigaddset(&winch, SIGWINCH);
2918 if (allow)
2919 sigprocmask(SIG_UNBLOCK, &winch, NULL);
2920 else
2921 sigprocmask(SIG_BLOCK, &winch, NULL);
2922}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002923#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002924
Chris Allegrettadab017e2002-04-23 10:56:06 +00002925#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002926void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002927{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002928 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002929
Chris Allegretta658399a2001-06-14 02:54:22 +00002930 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002931 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002932
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002933 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002934 case TOGGLE_SUSPEND_KEY:
2935 signal_init();
2936 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002937#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00002938 case TOGGLE_MOUSE_KEY:
2939 mouse_init();
2940 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002941#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002942 case TOGGLE_NOHELP_KEY:
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002943 blank_statusbar();
2944 blank_bottombars();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002945 wrefresh(bottomwin);
2946 window_init();
2947 edit_refresh();
2948 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002949 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002950 case TOGGLE_DOS_KEY:
2951 UNSET(MAC_FILE);
2952 break;
2953 case TOGGLE_MAC_KEY:
2954 UNSET(DOS_FILE);
2955 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002956#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002957 case TOGGLE_SYNTAX_KEY:
2958 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002959 break;
2960#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002961 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002962
Chris Allegretta6df90f52002-07-19 01:08:59 +00002963 /* We are assuming here that shortcut_init() above didn't free and
2964 * reallocate the toggles. */
2965 enabled = ISSET(which->flag);
2966 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2967 enabled = !enabled;
2968 statusbar("%s %s", which->desc,
2969 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002970}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002971#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002972
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002973void disable_signals(void)
2974{
2975 struct termios term;
2976
2977 tcgetattr(0, &term);
2978 term.c_lflag &= ~ISIG;
2979 tcsetattr(0, TCSANOW, &term);
2980}
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002981
2982#ifndef NANO_SMALL
2983void enable_signals(void)
2984{
2985 struct termios term;
2986
2987 tcgetattr(0, &term);
2988 term.c_lflag |= ISIG;
2989 tcsetattr(0, TCSANOW, &term);
2990}
2991#endif
2992
2993void disable_flow_control(void)
2994{
2995 struct termios term;
2996
2997 tcgetattr(0, &term);
2998 term.c_iflag &= ~(IXON|IXOFF);
2999 tcsetattr(0, TCSANOW, &term);
3000}
3001
3002void enable_flow_control(void)
3003{
3004 struct termios term;
3005
3006 tcgetattr(0, &term);
3007 term.c_iflag |= (IXON|IXOFF);
3008 tcsetattr(0, TCSANOW, &term);
3009}
3010
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003011int main(int argc, char *argv[])
3012{
3013 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003014 int startline = 0; /* Line to try and start at */
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003015 int modify_control_seq = 0;
Chris Allegretta09fc4302003-01-16 22:16:38 +00003016 int fill_flag_used = 0; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003017 const shortcut *s;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003018 int keyhandled = 0; /* Have we handled the keystroke yet? */
David Lawrence Ramseyf8ddf312004-01-09 22:38:09 +00003019 int kbinput; /* Input from keyboard */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003020 int meta_key;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003021
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003022#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003023 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003024#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003025#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003026 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003027 {"help", 0, 0, 'h'},
3028#ifdef ENABLE_MULTIBUFFER
3029 {"multibuffer", 0, 0, 'F'},
3030#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003031#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003032#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003033 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003034#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003035 {"ignorercfiles", 0, 0, 'I'},
3036#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003037#ifndef DISABLE_JUSTIFY
3038 {"quotestr", 1, 0, 'Q'},
3039#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003040#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003041 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003042#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003043 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003044 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003045#ifdef ENABLE_COLOR
3046 {"syntax", 1, 0, 'Y'},
3047#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003048 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003049 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003050 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003051#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003052 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003053#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003054#ifndef DISABLE_OPERATINGDIR
3055 {"operatingdir", 1, 0, 'o'},
3056#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003057 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003058#ifndef DISABLE_WRAPJUSTIFY
3059 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003060#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003061#ifndef DISABLE_SPELLER
3062 {"speller", 1, 0, 's'},
3063#endif
3064 {"tempfile", 0, 0, 't'},
3065 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003066#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003067 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003068#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003069 {"nohelp", 0, 0, 'x'},
3070 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003071#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003072 {"smarthome", 0, 0, 'A'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003073 {"backup", 0, 0, 'B'},
3074 {"dos", 0, 0, 'D'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003075 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003076 {"mac", 0, 0, 'M'},
3077 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003078 {"smooth", 0, 0, 'S'},
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003079 {"restricted", 0, 0, 'Z'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003080 {"autoindent", 0, 0, 'i'},
3081 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003082#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003083 {0, 0, 0, 0}
3084 };
3085#endif
3086
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003087#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003088 setlocale(LC_ALL, "");
3089 bindtextdomain(PACKAGE, LOCALEDIR);
3090 textdomain(PACKAGE);
3091#endif
3092
Chris Allegretta7662c862003-01-13 01:35:15 +00003093#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003094 /* if we don't have rcfile support, we're root, and
3095 --disable-wrapping-as-root is used, turn wrapping off */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003096 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003097 SET(NO_WRAP);
3098#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003099
3100#ifdef HAVE_GETOPT_LONG
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003101 while ((optchr = getopt_long(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz",
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003102 long_options, NULL)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003103#else
3104 while ((optchr =
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003105 getopt(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003106#endif
3107
3108 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003109
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003110 case 'a':
3111 case 'b':
3112 case 'e':
3113 case 'f':
3114 case 'g':
3115 case 'j':
3116 /* Pico compatibility flags */
3117 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003118#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003119 case 'A':
3120 SET(SMART_HOME);
3121 break;
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003122 case 'B':
3123 SET(BACKUP_FILE);
3124 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003125 case 'D':
3126 SET(DOS_FILE);
3127 break;
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003128 case 'E':
3129 backup_dir = mallocstrcpy(backup_dir, optarg);
3130 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003131#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003132#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003133 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003134 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003135 break;
3136#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003137#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003138#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003139 case 'H':
3140 SET(HISTORYLOG);
3141 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003142#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003143 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003144 SET(NO_RCFILE);
3145 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003146#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003147#ifndef NANO_SMALL
3148 case 'M':
3149 SET(MAC_FILE);
3150 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003151 case 'N':
3152 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003153 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003154#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003155#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003156 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003157 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003158 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003159#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003160#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003161 case 'R':
3162 SET(USE_REGEXP);
3163 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003164#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003165#ifndef NANO_SMALL
3166 case 'S':
3167 SET(SMOOTHSCROLL);
3168 break;
3169#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003170 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003171 {
3172 int i;
3173 char *first_error;
3174
Chris Allegretta7662c862003-01-13 01:35:15 +00003175 /* Using strtol() instead of atoi() lets us accept 0
3176 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003177 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003178 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003179 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003180 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003181 tabsize = i;
3182 if (tabsize <= 0) {
3183 fprintf(stderr, _("Tab size is too small for nano...\n"));
3184 exit(1);
3185 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003186 }
3187 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003188 case 'V':
3189 version();
3190 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003191#ifdef ENABLE_COLOR
3192 case 'Y':
3193 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3194 break;
3195#endif
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003196 case 'Z':
3197 SET(RESTRICTED);
3198 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003199 case 'c':
3200 SET(CONSTUPDATE);
3201 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003202 case 'd':
3203 SET(REBIND_DELETE);
3204 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003205#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003206 case 'i':
3207 SET(AUTOINDENT);
3208 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003209 case 'k':
3210 SET(CUT_TO_END);
3211 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003212#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003213 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003214 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003215 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003216#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003217 case 'm':
3218 SET(USE_MOUSE);
3219 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003220#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003221#ifndef DISABLE_OPERATINGDIR
3222 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003223 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003224 break;
3225#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003226 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003227 SET(PRESERVE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003228 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003229#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003230 case 'r':
3231 {
3232 int i;
3233 char *first_error;
3234
Chris Allegretta7662c862003-01-13 01:35:15 +00003235 /* Using strtol() instead of atoi() lets us accept 0
3236 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003237 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003238 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003239 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003240 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003241 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003242 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003243 fill_flag_used = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003244 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003245#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003246#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003247 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003248 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003249 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003250#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003251 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003252 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003253 break;
3254 case 'v':
3255 SET(VIEW_MODE);
3256 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003257#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003258 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003259 SET(NO_WRAP);
3260 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003261#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003262 case 'x':
3263 SET(NO_HELP);
3264 break;
3265 case 'z':
3266 SET(SUSPEND);
3267 break;
3268 default:
3269 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003270 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003271 }
3272
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003273 /* If filename starts with 'r', we use restricted mode. */
3274 if (*(tail(argv[0])) == 'r')
3275 SET(RESTRICTED);
3276
3277 /* If we're using restricted mode, disable suspending, backup files,
3278 * and reading rcfiles. */
3279 if (ISSET(RESTRICTED)) {
3280 UNSET(SUSPEND);
3281 UNSET(BACKUP_FILE);
3282 SET(NO_RCFILE);
3283 }
3284
Chris Allegretta7662c862003-01-13 01:35:15 +00003285/* We've read through the command line options. Now back up the flags
3286 and values that are set, and read the rcfile(s). If the values
3287 haven't changed afterward, restore the backed-up values. */
3288#ifdef ENABLE_NANORC
3289 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003290#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003291 char *operating_dir_cpy = operating_dir;
3292#endif
3293#ifndef DISABLE_WRAPPING
3294 int wrap_at_cpy = wrap_at;
3295#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003296#ifndef NANO_SMALL
3297 char *backup_dir_cpy = backup_dir;
3298#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003299#ifndef DISABLE_JUSTIFY
3300 char *quotestr_cpy = quotestr;
3301#endif
3302#ifndef DISABLE_SPELLER
3303 char *alt_speller_cpy = alt_speller;
3304#endif
3305 int tabsize_cpy = tabsize;
3306 long flags_cpy = flags;
3307
Chris Allegretta5ec68622003-02-05 02:39:34 +00003308#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003309 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003310#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003311#ifndef NANO_SMALL
3312 backup_dir = NULL;
3313#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003314#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003315 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003316#endif
3317#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003318 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003319#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003320
3321 do_rcfile();
3322
3323#ifndef DISABLE_OPERATINGDIR
3324 if (operating_dir_cpy != NULL) {
3325 free(operating_dir);
3326 operating_dir = operating_dir_cpy;
3327 }
3328#endif
3329#ifndef DISABLE_WRAPPING
3330 if (fill_flag_used)
3331 wrap_at = wrap_at_cpy;
3332#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003333#ifndef NANO_SMALL
3334 if (backup_dir_cpy != NULL) {
3335 free(backup_dir);
3336 backup_dir = backup_dir_cpy;
3337 }
3338#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003339#ifndef DISABLE_JUSTIFY
3340 if (quotestr_cpy != NULL) {
3341 free(quotestr);
3342 quotestr = quotestr_cpy;
3343 }
3344#endif
3345#ifndef DISABLE_SPELLER
3346 if (alt_speller_cpy != NULL) {
3347 free(alt_speller);
3348 alt_speller = alt_speller_cpy;
3349 }
3350#endif
3351 if (tabsize_cpy > 0)
3352 tabsize = tabsize_cpy;
3353 flags |= flags_cpy;
3354 }
3355#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003356 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003357 SET(NO_WRAP);
3358#endif
3359#endif /* ENABLE_NANORC */
3360
Chris Allegrettad8451932003-03-11 03:50:40 +00003361#ifndef NANO_SMALL
3362 history_init();
3363#ifdef ENABLE_NANORC
3364 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3365 load_history();
3366#endif
3367#endif
3368
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003369#ifndef NANO_SMALL
3370 /* Set up the backup directory. This entails making sure it exists
3371 * and is a directory, so that backup files will be saved there. */
3372 init_backup_dir();
3373#endif
3374
Chris Allegretta7662c862003-01-13 01:35:15 +00003375#ifndef DISABLE_OPERATINGDIR
3376 /* Set up the operating directory. This entails chdir()ing there,
3377 so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003378 init_operating_dir();
3379#endif
3380
Chris Allegretta7662c862003-01-13 01:35:15 +00003381#ifndef DISABLE_JUSTIFY
3382 if (quotestr == NULL)
3383#ifdef HAVE_REGEX_H
3384 quotestr = mallocstrcpy(NULL, "^([ \t]*[|>:}#])+");
3385#else
3386 quotestr = mallocstrcpy(NULL, "> ");
3387#endif
3388#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003389
Chris Allegretta7662c862003-01-13 01:35:15 +00003390 if (tabsize == -1)
3391 tabsize = 8;
3392
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003393 /* Clear the filename we'll be using */
3394 filename = charalloc(1);
3395 filename[0] = '\0';
3396
Chris Allegretta7662c862003-01-13 01:35:15 +00003397 /* If there's a +LINE flag, it is the first non-option argument. */
3398 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3399 startline = atoi(&argv[optind][1]);
3400 optind++;
3401 }
3402 if (0 < optind && optind < argc)
3403 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003404
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003405 /* See if there's a non-option in argv (first non-option is the
3406 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003407 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003408 /* Look for the +line flag... */
3409 if (argv[optind][0] == '+') {
3410 startline = atoi(&argv[optind][1]);
3411 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003412 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003413 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003414 } else
3415 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003416 }
3417
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003418 /* Back up the old terminal settings so that they can be restored. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003419 tcgetattr(0, &oldterm);
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003420
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003421 /* Curses initialization stuff: Start curses, save the state of the
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003422 * terminal mode, put the terminal in cbreak mode (read one character
3423 * at a time and interpret the special control keys), disable
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003424 * translation of carriage return (^M) into newline (^J) so that we
David Lawrence Ramseyfd462b12004-05-19 15:41:17 +00003425 * can tell the difference between the Enter key and Ctrl-J, and
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003426 * disable echoing of characters as they're typed. Finally, disable
3427 * interpretation of the special control keys, and if we're not in
3428 * preserve mode, disable interpretation of the flow control
3429 * characters too. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003430 initscr();
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003431 cbreak();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003432 nonl();
David Lawrence Ramseyd03216a2004-01-28 18:21:21 +00003433 noecho();
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003434 disable_signals();
3435 if (!ISSET(PRESERVE))
3436 disable_flow_control();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003437
3438#ifndef NANO_SMALL
3439 /* Save the terminal's current state, so that we can restore it
3440 * after a resize. */
3441 savetty();
3442#endif
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003443
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003444 /* Set up the global variables and the shortcuts. */
Chris Allegretta56214c62001-09-27 02:46:53 +00003445 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003446 shortcut_init(0);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003447
3448 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003449 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003450
3451#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003452 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003453#endif
3454
Chris Allegretta2a42af12000-09-12 23:02:49 +00003455 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003456#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003457 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003458#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003459
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003460#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003461 fprintf(stderr, "Main: bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003462#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003463 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003464 display_main_list();
3465
3466#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003467 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003468#endif
3469
David Lawrence Ramsey97133f52004-05-14 17:39:19 +00003470 open_file(filename, 0, 0);
Chris Allegretta7662c862003-01-13 01:35:15 +00003471#ifdef ENABLE_MULTIBUFFER
3472 /* If we're using multibuffers and more than one file is specified
3473 on the command line, load them all and switch to the first one
3474 afterward */
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003475 if (optind + 1 < argc) {
3476 int old_multibuffer = ISSET(MULTIBUFFER);
3477 SET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003478 for (optind++; optind < argc; optind++) {
3479 add_open_file(1);
3480 new_file();
3481 filename = mallocstrcpy(filename, argv[optind]);
3482 open_file(filename, 0, 0);
3483 load_file(0);
3484 }
3485 open_nextfile_void();
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003486 if (!old_multibuffer)
3487 UNSET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003488 }
3489#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003490
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003491 titlebar(NULL);
3492
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003493 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003494 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003495
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003496#ifndef NANO_SMALL
3497 /* Return here after a SIGWINCH. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003498 sigsetjmp(jmpbuf, 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003499#endif
Chris Allegretta08020882001-01-29 23:37:54 +00003500
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003501 /* SHUT UP GCC! */
3502 startline = 0;
3503 fill_flag_used = 0;
3504 keyhandled = 0;
3505
Chris Allegretta7662c862003-01-13 01:35:15 +00003506 /* This variable should be initialized after the sigsetjmp(), so we
3507 can't do Esc-Esc then quickly resize and muck things up. */
Chris Allegretta08020882001-01-29 23:37:54 +00003508 modify_control_seq = 0;
3509
Robert Siemborski6967eec2000-07-08 14:23:32 +00003510 edit_refresh();
3511 reset_cursor();
3512
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003513 while (TRUE) {
Chris Allegrettad0845df2003-02-13 00:56:57 +00003514 keyhandled = 0;
Chris Allegretta9239d742000-09-06 15:19:18 +00003515
Chris Allegrettad26ab912003-01-28 01:16:47 +00003516 if (ISSET(CONSTUPDATE))
3517 do_cursorpos(1);
3518
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003519#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003520 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003521#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003522
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003523 kbinput = get_kbinput(edit, &meta_key);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003524#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003525 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003526#endif
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003527 if (meta_key == TRUE) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003528 /* Check for the metaval and miscval defs... */
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003529 for (s = main_list; s != NULL; s = s->next)
David Lawrence Ramsey82138502003-12-24 08:03:54 +00003530 if ((s->metaval != NANO_NO_KEY && kbinput == s->metaval) ||
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003531 (s->miscval != NANO_NO_KEY && kbinput == s->miscval)) {
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003532 if (ISSET(VIEW_MODE) && !s->viewok)
3533 print_view_warning();
3534 else {
3535 if (s->func != do_cut_text)
3536 UNSET(KEEP_CUTBUFFER);
3537 s->func();
3538 }
3539 keyhandled = 1;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003540 }
3541#ifndef NANO_SMALL
3542 if (!keyhandled)
3543 /* And for toggle switches */
3544 for (t = toggles; t != NULL; t = t->next)
3545 if (kbinput == t->val) {
3546 UNSET(KEEP_CUTBUFFER);
3547 do_toggle(t);
3548 keyhandled = 1;
3549 }
3550#endif
3551#ifdef DEBUG
3552 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput,
3553 kbinput);
3554#endif
3555 }
3556
3557 /* Look through the main shortcut list to see if we've hit a
3558 shortcut key or function key */
3559
3560 if (!keyhandled)
3561#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
3562 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
3563#else
3564 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
3565#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003566 if ((s->ctrlval != NANO_NO_KEY && kbinput == s->ctrlval) ||
3567 (s->funcval != NANO_NO_KEY && kbinput == s->funcval)) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003568 if (ISSET(VIEW_MODE) && !s->viewok)
3569 print_view_warning();
3570 else {
3571 if (s->func != do_cut_text)
3572 UNSET(KEEP_CUTBUFFER);
3573 s->func();
3574 }
3575 keyhandled = 1;
3576 /* Break out explicitly once we successfully handle
3577 a shortcut */
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003578 break;
3579 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003580 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003581
3582 if (!keyhandled)
3583 UNSET(KEEP_CUTBUFFER);
Chris Allegrettae42df732002-10-15 00:27:55 +00003584
Chris Allegrettae42df732002-10-15 00:27:55 +00003585 /* Don't even think about changing this string */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003586 if (kbinput == NANO_CONTROL_Q)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003587 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003588 if (kbinput == NANO_CONTROL_S)
3589 statusbar(_("XOFF ignored, mumble mumble."));
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003590
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003591 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3592 Control-S and Control-Q */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003593 if (kbinput == NANO_CONTROL_Q || kbinput == NANO_CONTROL_S)
Chris Allegretta9239d742000-09-06 15:19:18 +00003594 keyhandled = 1;
3595
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003596 /* Catch ^Z by hand when triggered also */
3597 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003598 if (ISSET(SUSPEND))
3599 do_suspend(0);
3600 keyhandled = 1;
3601 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003602
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003603 /* Last gasp, stuff that's not in the main lists */
3604 if (!keyhandled)
3605 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003606#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003607 case KEY_MOUSE:
3608 do_mouse();
3609 break;
3610#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003611
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003612 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3613 * have been handled before we
3614 * got here */
3615 case NANO_CONTROL_5: /* Ctrl-] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003616 break;
3617 default:
3618#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003619 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003620#endif
3621 /* We no longer stop unhandled sequences so that people with
3622 odd character sets can type... */
3623
Chris Allegretta7662c862003-01-13 01:35:15 +00003624 if (ISSET(VIEW_MODE))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003625 print_view_warning();
Chris Allegretta7662c862003-01-13 01:35:15 +00003626 else
3627 do_char(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003628 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003629
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003630 reset_cursor();
3631 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003632 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003633 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003634}