blob: 3cec1a254dbb6a05bc188e5fb75193372c2bbe8f [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 Ramsey32e3b882004-05-29 01:20:17 +0000158 /* If we're using restricted mode, don't write any emergency backup
159 * files, since that would allow reading from or writing to files
160 * not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000161 if (ISSET(RESTRICTED))
162 return;
163
Chris Allegretta6df90f52002-07-19 01:08:59 +0000164 /* If we can't save, we have REAL bad problems, but we might as well
165 TRY. */
166 if (die_filename[0] == '\0')
167 ret = get_next_filename("nano.save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000168 else {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000169 char *buf = charalloc(strlen(die_filename) + 6);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000170
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000171 strcpy(buf, die_filename);
172 strcat(buf, ".save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000173 ret = get_next_filename(buf);
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000174 free(buf);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000175 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000176 if (ret[0] != '\0')
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +0000177 i = write_file(ret, TRUE, FALSE, TRUE);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000178
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000179 if (i != -1)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000180 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000181 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000182 fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000183
184 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000185}
186
Chris Allegrettae61e8302001-01-14 05:18:27 +0000187/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000188 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000189void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000190{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000191 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000192}
193
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000194void print_view_warning(void)
195{
196 statusbar(_("Key illegal in VIEW mode"));
197}
198
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +0000199/* Initialize global variables -- no better way for now. If
Chris Allegretta6df90f52002-07-19 01:08:59 +0000200 * save_cutbuffer is nonzero, don't set cutbuffer to NULL. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000201void global_init(int save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000202{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000203 current_x = 0;
204 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000205
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000206 editwinrows = LINES - 5 + no_help();
207 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000208 die_too_small();
209
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000210 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000211 if (!save_cutbuffer)
212 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000213 current = NULL;
214 edittop = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000215 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000216 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000217 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000218
Chris Allegretta6fe61492001-05-21 12:56:25 +0000219#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000220 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000221 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000222 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000223 if (fill < 0)
224 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000225#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000226
Chris Allegretta88b09152001-05-17 11:35:43 +0000227 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000228 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000229 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000230}
231
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000232void window_init(void)
233{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000234 editwinrows = LINES - 5 + no_help();
235 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000236 die_too_small();
237
Chris Allegretta1a128af2003-01-26 04:15:56 +0000238 if (topwin != NULL)
239 delwin(topwin);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000240 if (edit != NULL)
241 delwin(edit);
Chris Allegretta1a128af2003-01-26 04:15:56 +0000242 if (bottomwin != NULL)
243 delwin(bottomwin);
244
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000245 /* Set up the windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000246 topwin = newwin(2, COLS, 0, 0);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000247 edit = newwin(editwinrows, COLS, 2, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000248 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
249
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000250 /* Turn the keypad back on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000251 keypad(edit, TRUE);
252 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000253}
254
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000255#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000256void mouse_init(void)
257{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000258 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000259 mousemask(BUTTON1_RELEASED, NULL);
260 mouseinterval(50);
261 } else
262 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000263}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000264#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000265
266#ifndef DISABLE_HELP
267/* This function allocates help_text, and stores the help string in it.
268 * help_text should be NULL initially. */
269void help_init(void)
270{
Chris Allegretta908f7702003-01-15 11:18:58 +0000271 size_t allocsize = 1; /* space needed for help_text */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000272 char *ptr = NULL;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000273 const shortcut *s;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000274#ifndef NANO_SMALL
275 const toggle *t;
276#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000277
278 /* First set up the initial help text for the current function */
279 if (currshortcut == whereis_list || currshortcut == replace_list
280 || currshortcut == replace_list_2)
281 ptr = _("Search Command Help Text\n\n "
282 "Enter the words or characters you would like to search "
283 "for, then hit enter. If there is a match for the text you "
284 "entered, the screen will be updated to the location of the "
285 "nearest match for the search string.\n\n "
Chris Allegretta37d594c2003-01-05 22:00:41 +0000286 "The previous search string will be shown in brackets after "
287 "the Search: prompt. Hitting Enter without entering any text "
288 "will perform the previous search.\n\n The following function "
289 "keys are available in Search mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000290 else if (currshortcut == goto_list)
291 ptr = _("Go To Line Help Text\n\n "
292 "Enter the line number that you wish to go to and hit "
293 "Enter. If there are fewer lines of text than the "
294 "number you entered, you will be brought to the last line "
295 "of the file.\n\n The following function keys are "
296 "available in Go To Line mode:\n\n");
297 else if (currshortcut == insertfile_list)
298 ptr = _("Insert File Help Text\n\n "
299 "Type in the name of a file to be inserted into the current "
300 "file buffer at the current cursor location.\n\n "
301 "If you have compiled nano with multiple file buffer "
302 "support, and enable multiple buffers with the -F "
303 "or --multibuffer command line flags, the Meta-F toggle, or "
304 "a nanorc file, inserting a file will cause it to be "
305 "loaded into a separate buffer (use Meta-< and > to switch "
306 "between file buffers).\n\n If you need another blank "
307 "buffer, do not enter any filename, or type in a "
308 "nonexistent filename at the prompt and press "
309 "Enter.\n\n The following function keys are "
310 "available in Insert File mode:\n\n");
311 else if (currshortcut == writefile_list)
312 ptr = _("Write File Help Text\n\n "
313 "Type the name that you wish to save the current file "
314 "as and hit Enter to save the file.\n\n If you have "
315 "selected text with Ctrl-^, you will be prompted to "
316 "save only the selected portion to a separate file. To "
317 "reduce the chance of overwriting the current file with "
318 "just a portion of it, the current filename is not the "
319 "default in this mode.\n\n The following function keys "
320 "are available in Write File mode:\n\n");
321#ifndef DISABLE_BROWSER
322 else if (currshortcut == browser_list)
323 ptr = _("File Browser Help Text\n\n "
324 "The file browser is used to visually browse the "
325 "directory structure to select a file for reading "
326 "or writing. You may use the arrow keys or Page Up/"
327 "Down to browse through the files, and S or Enter to "
328 "choose the selected file or enter the selected "
329 "directory. To move up one level, select the directory "
330 "called \"..\" at the top of the file list.\n\n The "
331 "following function keys are available in the file "
332 "browser:\n\n");
333 else if (currshortcut == gotodir_list)
334 ptr = _("Browser Go To Directory Help Text\n\n "
335 "Enter the name of the directory you would like to "
336 "browse to.\n\n If tab completion has not been disabled, "
337 "you can use the TAB key to (attempt to) automatically "
338 "complete the directory name.\n\n The following function "
339 "keys are available in Browser Go To Directory mode:\n\n");
340#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000341#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000342 else if (currshortcut == spell_list)
343 ptr = _("Spell Check Help Text\n\n "
344 "The spell checker checks the spelling of all text "
345 "in the current file. When an unknown word is "
346 "encountered, it is highlighted and a replacement can "
347 "be edited. It will then prompt to replace every "
348 "instance of the given misspelled word in the "
349 "current file.\n\n The following other functions are "
350 "available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000351#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000352#ifndef NANO_SMALL
353 else if (currshortcut == extcmd_list)
354 ptr = _("External Command Help Text\n\n "
355 "This menu allows you to insert the output of a command "
356 "run by the shell into the current buffer (or a new "
357 "buffer in multibuffer mode).\n\n The following keys are "
358 "available in this mode:\n\n");
359#endif
360 else /* Default to the main help list */
361 ptr = _(" nano help text\n\n "
362 "The nano editor is designed to emulate the functionality and "
363 "ease-of-use of the UW Pico text editor. There are four main "
364 "sections of the editor: The top line shows the program "
365 "version, the current filename being edited, and whether "
366 "or not the file has been modified. Next is the main editor "
367 "window showing the file being edited. The status line is "
368 "the third line from the bottom and shows important messages. "
369 "The bottom two lines show the most commonly used shortcuts "
370 "in the editor.\n\n "
371 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000372 "sequences are notated with a caret (^) symbol and can be "
373 "entered either by using the Control (Ctrl) key or pressing the "
374 "Esc key twice. Escape-key sequences are notated with the Meta "
375 "(M) symbol and can be entered using either the Esc, Alt or "
376 "Meta key depending on your keyboard setup. Also, pressing Esc "
377 "twice and then typing a three-digit number from 000 to 255 "
378 "will enter the character with the corresponding ASCII code. "
379 "The following keystrokes are available in the main editor "
380 "window. Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000381
Chris Allegretta908f7702003-01-15 11:18:58 +0000382 allocsize += strlen(ptr);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000383
384 /* The space needed for the shortcut lists, at most COLS characters,
385 * plus '\n'. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000386 allocsize += (COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000387
388#ifndef NANO_SMALL
389 /* If we're on the main list, we also count the toggle help text.
390 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
391 * COLS - 24 characters, plus '\n'.*/
Chris Allegretta3a784062003-02-10 02:32:58 +0000392 if (currshortcut == main_list) {
393 size_t endislen = strlen(_("enable/disable"));
394
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000395 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000396 allocsize += 8 + strlen(t->desc) + endislen;
397 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000398#endif /* !NANO_SMALL */
399
400 /* help_text has been freed and set to NULL unless the user resized
401 * while in the help screen. */
402 free(help_text);
403
404 /* Allocate space for the help text */
Chris Allegretta908f7702003-01-15 11:18:58 +0000405 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000406
407 /* Now add the text we want */
408 strcpy(help_text, ptr);
409 ptr = help_text + strlen(help_text);
410
411 /* Now add our shortcut info */
412 for (s = currshortcut; s != NULL; s = s->next) {
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000413 /* true if the character in s->metaval is shown in first column */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000414 int meta_shortcut = 0;
415
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000416 if (s->ctrlval != NANO_NO_KEY) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000417#ifndef NANO_SMALL
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000418 if (s->ctrlval == NANO_HISTORY_KEY)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000419 ptr += sprintf(ptr, "%.2s", _("Up"));
420 else
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000421#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000422 if (s->ctrlval == NANO_CONTROL_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000423 ptr += sprintf(ptr, "^%.5s", _("Space"));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000424 else if (s->ctrlval == NANO_CONTROL_8)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000425 ptr += sprintf(ptr, "^?");
426 else
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000427 ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000428 }
429#ifndef NANO_SMALL
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000430 else if (s->metaval != NANO_NO_KEY) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000431 meta_shortcut = 1;
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000432 if (s->metaval == NANO_ALT_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000433 ptr += snprintf(ptr, 8, "M-%.5s", _("Space"));
434 else
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000435 ptr += sprintf(ptr, "M-%c", toupper(s->metaval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000436 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000437#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000438
439 *(ptr++) = '\t';
440
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000441 if (s->funcval != NANO_NO_KEY)
442 ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000443
444 *(ptr++) = '\t';
445
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000446 if (!meta_shortcut && s->metaval != NANO_NO_KEY)
447 ptr += sprintf(ptr, "(M-%c)", toupper(s->metaval));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000448 else if (meta_shortcut && s->miscval != NANO_NO_KEY)
449 ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000450
451 *(ptr++) = '\t';
452
453 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000454 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000455 }
456
457#ifndef NANO_SMALL
458 /* And the toggles... */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000459 if (currshortcut == main_list) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000460 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000461 assert(t->desc != NULL);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000462 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val), t->desc,
Chris Allegretta3a784062003-02-10 02:32:58 +0000463 _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000464 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000465 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000466#endif /* !NANO_SMALL */
467
468 /* If all went well, we didn't overwrite the allocated space for
469 help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000470 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000471}
472#endif
473
474/* Create a new filestruct node. Note that we specifically do not set
475 * prevnode->next equal to the new line. */
476filestruct *make_new_node(filestruct *prevnode)
477{
478 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
479
480 newnode->data = NULL;
481 newnode->prev = prevnode;
482 newnode->next = NULL;
483 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
484
485 return newnode;
486}
487
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000488/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000489filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000490{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000491 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000492
Chris Allegretta6df90f52002-07-19 01:08:59 +0000493 assert(src != NULL);
494
Chris Allegretta88b09152001-05-17 11:35:43 +0000495 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000496 dst->next = src->next;
497 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000498 strcpy(dst->data, src->data);
499 dst->lineno = src->lineno;
500
501 return dst;
502}
503
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000504/* Splice a node into an existing filestruct. */
505void splice_node(filestruct *begin, filestruct *newnode, filestruct *end)
506{
507 if (newnode != NULL) {
508 newnode->next = end;
509 newnode->prev = begin;
510 }
511 if (begin != NULL)
512 begin->next = newnode;
513 if (end != NULL)
514 end->prev = newnode;
515}
516
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000517/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000518void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000519{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000520 assert(fileptr != NULL);
521
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000522 if (fileptr->prev != NULL)
523 fileptr->prev->next = fileptr->next;
524
525 if (fileptr->next != NULL)
526 fileptr->next->prev = fileptr->prev;
527}
528
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000529/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000530void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000531{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000532 if (fileptr != NULL) {
533 if (fileptr->data != NULL)
534 free(fileptr->data);
535 free(fileptr);
536 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000537}
538
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000539/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000540filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000541{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000542 filestruct *head; /* copy of src, top of the copied list */
543 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000544
Chris Allegretta6df90f52002-07-19 01:08:59 +0000545 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000546
Chris Allegretta6df90f52002-07-19 01:08:59 +0000547 prev = copy_node(src);
548 prev->prev = NULL;
549 head = prev;
550 src = src->next;
551 while (src != NULL) {
552 prev->next = copy_node(src);
553 prev->next->prev = prev;
554 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000555
Chris Allegretta6df90f52002-07-19 01:08:59 +0000556 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000557 }
558
Chris Allegretta6df90f52002-07-19 01:08:59 +0000559 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000560 return head;
561}
562
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000563/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000564void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000565{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000566 if (src != NULL) {
567 while (src->next != NULL) {
568 src = src->next;
569 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000570#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000571 fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_node()");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000572#endif
573 }
574 delete_node(src);
575#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000576 fprintf(stderr, "%s: free'd last node.\n", "delete_node()");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000577#endif
578 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000579}
580
Chris Allegretta6df90f52002-07-19 01:08:59 +0000581void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000582{
583 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000584 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000585
Chris Allegretta6df90f52002-07-19 01:08:59 +0000586 assert(fileage == NULL || fileage != fileage->next);
587 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000588 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000589}
590
Chris Allegretta6df90f52002-07-19 01:08:59 +0000591void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000592{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000593 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000594 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000595 else {
596 int lineno = fileptr->prev->lineno;
597
598 assert(fileptr != fileptr->next);
599 for (; fileptr != NULL; fileptr = fileptr->next)
600 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000601 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000602}
603
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000604/* Print one usage string to the screen, removes lots of duplicate
Chris Allegretta6df90f52002-07-19 01:08:59 +0000605 * strings to translate and takes out the parts that shouldn't be
606 * translatable (the flag names). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000607void print1opt(const char *shortflag, const char *longflag,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000608 const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000609{
610 printf(" %s\t", shortflag);
611 if (strlen(shortflag) < 8)
612 printf("\t");
613
614#ifdef HAVE_GETOPT_LONG
615 printf("%s\t", longflag);
616 if (strlen(longflag) < 8)
617 printf("\t\t");
618 else if (strlen(longflag) < 16)
619 printf("\t");
620#endif
621
622 printf("%s\n", desc);
623}
624
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000625void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000626{
627#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000628 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
629 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000630#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000631 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
632 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000633#endif /* HAVE_GETOPT_LONG */
634
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000635 print1opt("-h, -?", "--help", _("Show this message"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000636 print1opt(_("+LINE"), "", _("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000637#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +0000638 print1opt("-A", "--smarthome", _("Enable smart home key"));
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000639 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000640 print1opt("-D", "--dos", _("Write file in DOS format"));
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +0000641 print1opt("-E", "--backupdir=[dir]", _("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000642#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000643#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000644 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000645#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000646#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000647#ifndef NANO_SMALL
Chris Allegretta36fec722003-01-22 01:13:25 +0000648 print1opt("-H", "--historylog", _("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000649#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000650 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
651#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000652#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000653 print1opt("-M", "--mac", _("Write file in Mac format"));
654 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000655#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000656#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000657 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000658#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000659#ifdef HAVE_REGEX_H
660 print1opt("-R", "--regexp", _("Do regular expression searches"));
661#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000662#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000663 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000664#endif
David Lawrence Ramseya7c93642004-02-25 03:19:29 +0000665 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), _("Set width of a tab in cols to #cols"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000666 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000667#ifdef ENABLE_COLOR
668 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
669#endif
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000670 print1opt(_("-Z"), _("--restricted"), _("Restricted mode"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000671 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000672#ifndef NANO_SMALL
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000673 print1opt("-d", "--rebinddelete", _("Fix Backspace/Delete confusion problem"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000674 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
675 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000676#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000677 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000678#ifndef DISABLE_MOUSE
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000679 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000680#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000681#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000682 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000683#endif
Jordi Mallacheeb50042003-01-18 22:42:34 +0000684 print1opt("-p", "--preserve", _("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000685#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000686 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000687#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000688#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000689 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000690#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000691 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
692 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000693#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000694 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000695#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000696 print1opt("-x", "--nohelp", _("Don't show help window"));
697 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000698
699 /* this is a special case */
700 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000701
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000702 exit(0);
703}
704
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000705void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000706{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000707 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000708 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000709 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000710 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000711 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000712
Chris Allegrettae6600372003-01-17 03:39:41 +0000713#ifndef ENABLE_NLS
714 printf(" --disable-nls");
715#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000716#ifdef DEBUG
717 printf(" --enable-debug");
718#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000719#ifdef NANO_EXTRA
720 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000721#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000722#ifdef NANO_SMALL
723 printf(" --enable-tiny");
724#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000725#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000726 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000727#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000728#ifdef DISABLE_HELP
729 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000730#endif
731#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000732 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000733#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000734#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +0000735 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000736#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000737#ifdef DISABLE_OPERATINGDIR
738 printf(" --disable-operatingdir");
739#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000740#ifdef DISABLE_SPELLER
741 printf(" --disable-speller");
742#endif
743#ifdef DISABLE_TABCOMP
744 printf(" --disable-tabcomp");
745#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000746#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000747#ifdef DISABLE_WRAPPING
748 printf(" --disable-wrapping");
749#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000750#ifdef DISABLE_ROOTWRAP
751 printf(" --disable-wrapping-as-root");
752#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000753#ifdef ENABLE_COLOR
754 printf(" --enable-color");
755#endif
756#ifdef ENABLE_MULTIBUFFER
757 printf(" --enable-multibuffer");
758#endif
759#ifdef ENABLE_NANORC
760 printf(" --enable-nanorc");
761#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000762#ifdef USE_SLANG
763 printf(" --with-slang");
764#endif
765 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000766}
767
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000768int no_help(void)
769{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000770 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000771}
772
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000773int nano_disabled_msg(void)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000774{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000775 statusbar(_("Sorry, support for this function has been disabled"));
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000776 return 1;
Chris Allegrettaff269f82000-12-01 18:46:01 +0000777}
778
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000779#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000780static int pid; /* This is the PID of the newly forked process
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000781 * below. It must be global since the signal
782 * handler needs it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000783RETSIGTYPE cancel_fork(int signal)
784{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000785 if (kill(pid, SIGKILL) == -1)
786 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000787}
788
789int open_pipe(const char *command)
790{
791 int fd[2];
792 FILE *f;
793 struct sigaction oldaction, newaction;
794 /* original and temporary handlers for SIGINT */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000795 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000796 /* cancel_sigs == 1 means that sigaction() failed without changing
797 * the signal handlers. cancel_sigs == 2 means the signal handler
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000798 * was changed, but the tcsetattr() didn't succeed.
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000799 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000800 * I use this variable since it is important to put things back when
801 * we finish, even if we get errors. */
802
803 /* Make our pipes. */
804
805 if (pipe(fd) == -1) {
806 statusbar(_("Could not pipe"));
807 return 1;
808 }
809
810 /* Fork a child. */
811
812 if ((pid = fork()) == 0) {
813 close(fd[0]);
814 dup2(fd[1], fileno(stdout));
815 dup2(fd[1], fileno(stderr));
816 /* If execl() returns at all, there was an error. */
817
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000818 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000819 exit(0);
820 }
821
822 /* Else continue as parent. */
823
824 close(fd[1]);
825
826 if (pid == -1) {
827 close(fd[0]);
828 statusbar(_("Could not fork"));
829 return 1;
830 }
831
832 /* Before we start reading the forked command's output, we set
833 * things up so that ^C will cancel the new process. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000834
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000835 /* Enable interpretation of the special control keys so that we get
836 * SIGINT when Ctrl-C is pressed. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000837 enable_signals();
838
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000839 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000840 cancel_sigs = 1;
841 nperror("sigaction");
842 } else {
843 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000844 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000845 cancel_sigs = 1;
846 nperror("sigaction");
847 }
848 }
849 /* Note that now oldaction is the previous SIGINT signal handler,
850 * to be restored later. */
851
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000852 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000853 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000854 nperror("fdopen");
855
856 read_file(f, "stdin", 0);
857 /* if multibuffer mode is on, we could be here in view mode; if so,
858 don't set the modification flag */
859 if (!ISSET(VIEW_MODE))
860 set_modified();
861
862 if (wait(NULL) == -1)
863 nperror("wait");
864
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000865 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000866 nperror("sigaction");
867
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000868 /* Disable interpretation of the special control keys so that we can
869 * use Ctrl-C for other things. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000870 disable_signals();
871
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000872 return 0;
873}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +0000874#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000875
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000876#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000877void do_mouse(void)
878{
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000879 int mouse_x, mouse_y;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000880
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000881 if (get_mouseinput(&mouse_x, &mouse_y, 1) == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000882
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000883 /* Click in the edit window to move the cursor, but only when
884 we're not in a subfunction. */
885 if (wenclose(edit, mouse_y, mouse_x) && currshortcut == main_list) {
886 int sameline;
887 /* Did they click on the line with the cursor? If they
888 clicked on the cursor, we set the mark. */
889 size_t xcur;
890 /* The character they clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000891
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000892 /* Subtract out size of topwin. Perhaps we need a constant
893 somewhere? */
894 mouse_y -= 2;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000895
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000896 sameline = (mouse_y == current_y);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000897
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000898 /* Move to where the click occurred. */
899 for (; current_y < mouse_y && current->next != NULL; current_y++)
900 current = current->next;
901 for (; current_y > mouse_y && current->prev != NULL; current_y--)
902 current = current->prev;
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000903
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000904 xcur = actual_x(current->data, get_page_start(xplustabs()) +
905 mouse_x);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000906
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000907 /* Selecting where the cursor is toggles the mark. As does
908 selecting beyond the line length with the cursor at the
909 end of the line. */
910 if (sameline && xcur == current_x) {
911 if (ISSET(VIEW_MODE)) {
912 print_view_warning();
913 return;
914 }
915 do_mark();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000916 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000917
918 current_x = xcur;
919 placewewant = xplustabs();
920 edit_refresh();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000921 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000922 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000923 /* FIXME: If we clicked on a location in the statusbar, the cursor
924 should move to the location we clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000925}
926#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000927
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000928/* The user typed a character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000929void do_char(char ch)
930{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000931 size_t current_len = strlen(current->data);
932#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000933 int do_refresh = FALSE;
934 /* Do we have to call edit_refresh(), or can we get away with
Chris Allegretta6df90f52002-07-19 01:08:59 +0000935 * update_line()? */
936#endif
937
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000938 if (ch == '\0') /* Null to newline, if needed. */
939 ch = '\n';
940 else if (ch == '\n') { /* Newline to Enter, if needed. */
941 do_enter();
942 return;
943 }
944
945 assert(current != NULL && current->data != NULL);
946
947 /* When a character is inserted on the current magicline, it means
948 * we need a new one! */
David Lawrence Ramseyb9775152004-03-19 02:15:42 +0000949 if (filebot == current)
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000950 new_magicline();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000951
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000952 /* More dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000953 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000954 assert(current_x <= current_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000955 charmove(&current->data[current_x + 1], &current->data[current_x],
956 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000957 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000958 totsize++;
959 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000960
Chris Allegretta6df90f52002-07-19 01:08:59 +0000961#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000962 /* Note that current_x has not yet been incremented. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000963 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000964 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +0000965#endif
966
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000967 do_right(FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000968
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000969#ifndef DISABLE_WRAPPING
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000970 /* If we're wrapping text, we need to call edit_refresh(). */
Chris Allegrettadffa2072002-07-24 01:02:26 +0000971 if (!ISSET(NO_WRAP) && ch != '\t')
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000972 do_refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000973#endif
974
Chris Allegretta6df90f52002-07-19 01:08:59 +0000975#ifdef ENABLE_COLOR
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000976 /* If color syntaxes are turned on, we need to call
977 * edit_refresh(). */
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +0000978 if (ISSET(COLOR_SYNTAX))
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000979 do_refresh = TRUE;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000980#endif
981
982#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000983 if (do_refresh)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000984 edit_refresh();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000985 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000986#endif
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000987 update_line(current, current_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000988}
989
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000990int do_verbatim_input(void)
991{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000992 int *v_kbinput = NULL; /* Used to hold verbatim input. */
993 size_t v_len; /* Length of verbatim input. */
David Lawrence Ramsey805547f2004-04-22 03:41:04 +0000994 size_t i;
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000995
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000996 statusbar(_("Verbatim input"));
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000997
998 v_kbinput = get_verbatim_kbinput(edit, v_kbinput, &v_len, TRUE);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000999
1000 /* Turn on DISABLE_CURPOS while inserting character(s) and turn it
1001 * off afterwards, so that if constant cursor position display is
1002 * on, it will be updated properly. */
1003 SET(DISABLE_CURPOS);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001004 for (i = 0; i < v_len; i++)
1005 do_char((char)v_kbinput[i]);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001006 UNSET(DISABLE_CURPOS);
1007
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001008 free(v_kbinput);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001009
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001010 return 1;
1011}
1012
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001013int do_backspace(void)
1014{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001015 if (current != fileage || current_x > 0) {
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001016 do_left(FALSE);
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001017 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001018 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001019 return 1;
1020}
1021
1022int do_delete(void)
1023{
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001024 int do_refresh = FALSE;
1025 /* Do we have to call edit_refresh(), or can we get away with
1026 * update_line()? */
1027
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001028 assert(current != NULL && current->data != NULL && current_x <=
1029 strlen(current->data));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001030
1031 placewewant = xplustabs();
1032
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001033 if (current->data[current_x] != '\0') {
1034 size_t linelen = strlen(current->data + current_x);
1035
1036 assert(current_x < strlen(current->data));
1037
1038 /* Let's get dangerous. */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001039 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001040 linelen);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001041
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001042 null_at(&current->data, linelen + current_x - 1);
1043#ifndef NANO_SMALL
1044 if (current_x < mark_beginx && mark_beginbuf == current)
1045 mark_beginx--;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001046#endif
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001047 } else if (current != filebot && (current->next != filebot ||
1048 current->data[0] == '\0')) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001049 /* We can delete the line before filebot only if it is blank: it
David Lawrence Ramsey32d19ce2004-05-24 05:05:07 +00001050 * becomes the new magicline then. */
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001051 filestruct *foo = current->next;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001052
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001053 assert(current_x == strlen(current->data));
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001054
1055 /* If we're deleting at the end of a line, we need to call
1056 * edit_refresh(). */
1057 if (current->data[current_x] == '\0')
1058 do_refresh = TRUE;
1059
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001060 current->data = charealloc(current->data, current_x +
1061 strlen(foo->data) + 1);
1062 strcpy(current->data + current_x, foo->data);
1063#ifndef NANO_SMALL
1064 if (mark_beginbuf == current->next) {
1065 mark_beginx += current_x;
1066 mark_beginbuf = current;
1067 }
1068#endif
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001069 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001070 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001071
1072 unlink_node(foo);
1073 delete_node(foo);
1074 renumber(current);
1075 totlines--;
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001076 wrap_reset();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001077 } else
1078 return 0;
1079
1080 totsize--;
1081 set_modified();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001082
1083#ifdef ENABLE_COLOR
1084 /* If color syntaxes are turned on, we need to call
1085 * edit_refresh(). */
1086 if (ISSET(COLOR_SYNTAX))
1087 do_refresh = TRUE;
1088#endif
1089
1090 if (do_refresh)
1091 edit_refresh();
1092 else
1093 update_line(current, current_x);
1094
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001095 return 1;
1096}
1097
1098int do_tab(void)
1099{
1100 do_char('\t');
1101 return 1;
1102}
1103
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001104/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001105int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001106{
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001107 filestruct *newnode = make_new_node(current);
1108 size_t extra = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001109
Chris Allegretta6df90f52002-07-19 01:08:59 +00001110 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001111
Chris Allegrettaff989832001-09-17 13:48:00 +00001112#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001113 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001114 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001115 /* If we are breaking the line in the indentation, the new
1116 * indentation should have only current_x characters, and
1117 * current_x should not change. */
1118 extra = indent_length(current->data);
1119 if (extra > current_x)
Chris Allegrettadab017e2002-04-23 10:56:06 +00001120 extra = current_x;
Chris Allegrettadab017e2002-04-23 10:56:06 +00001121 totsize += extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001122 }
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001123#endif
1124 newnode->data = charalloc(strlen(current->data + current_x) +
1125 extra + 1);
1126 strcpy(&newnode->data[extra], current->data + current_x);
1127#ifndef NANO_SMALL
1128 if (ISSET(AUTOINDENT))
1129 strncpy(newnode->data, current->data, extra);
1130#endif
1131 null_at(&current->data, current_x);
1132#ifndef NANO_SMALL
1133 if (current == mark_beginbuf && current_x < mark_beginx) {
1134 mark_beginbuf = newnode;
1135 mark_beginx += extra - current_x;
1136 }
1137#endif
1138 current_x = extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001139
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001140 if (current == filebot)
Chris Allegrettae3167732001-03-18 16:59:34 +00001141 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001142 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001143
1144 totsize++;
1145 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001146 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001147
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001148#ifndef NANO_SMALL
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001149 /* If we're in smooth scrolling mode and we're on the last line of
1150 * the edit window, move edittop down one line so that current is
1151 * onscreen. This prevents edit_refresh() from centering the
1152 * screen. */
1153 if (ISSET(SMOOTHSCROLL) && current_y == editwinrows - 1)
1154 edittop = edittop->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001155#endif
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001156 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001157
1158 totlines++;
1159 set_modified();
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001160 placewewant = xplustabs();
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001161
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001162 return 1;
1163}
1164
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001165#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001166int do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001167{
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001168 const filestruct *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001169 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001170
Chris Allegretta6df90f52002-07-19 01:08:59 +00001171 /* Skip letters in this word first. */
1172 while (current->data[current_x] != '\0' &&
1173 isalnum((int)current->data[current_x]))
1174 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001175
Chris Allegretta6df90f52002-07-19 01:08:59 +00001176 for (; current != NULL; current = current->next) {
1177 while (current->data[current_x] != '\0' &&
1178 !isalnum((int)current->data[current_x]))
1179 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001180
Chris Allegretta6df90f52002-07-19 01:08:59 +00001181 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001182 break;
1183
Chris Allegretta6df90f52002-07-19 01:08:59 +00001184 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001185 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001186 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001187 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001188
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001189 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001190
David Lawrence Ramseybf3c93e2004-03-13 19:42:58 +00001191 /* Refresh the screen. If current has run off the bottom, this
1192 * call puts it at the center line. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001193 edit_redraw(current_save);
David Lawrence Ramseybf3c93e2004-03-13 19:42:58 +00001194
Chris Allegretta6232d662002-05-12 19:52:15 +00001195 return 0;
1196}
1197
Chris Allegretta6df90f52002-07-19 01:08:59 +00001198/* The same thing for backwards. */
1199int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001200{
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001201 const filestruct *current_save = current;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001202 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001203
Chris Allegretta6df90f52002-07-19 01:08:59 +00001204 /* Skip letters in this word first. */
1205 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1206 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001207
Chris Allegretta6df90f52002-07-19 01:08:59 +00001208 for (; current != NULL; current = current->prev) {
1209 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1210 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001211
Chris Allegretta6df90f52002-07-19 01:08:59 +00001212 if (current_x >= 0)
1213 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001214
Chris Allegretta6df90f52002-07-19 01:08:59 +00001215 if (current->prev != NULL)
1216 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001217 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001218
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001219 if (current == NULL) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001220 current = fileage;
1221 current_x = 0;
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001222 } else {
1223 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1224 current_x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001225 }
1226
Chris Allegretta76e291b2001-10-14 19:05:10 +00001227 placewewant = xplustabs();
1228
David Lawrence Ramseyb6aa4282004-03-14 01:42:17 +00001229 /* Refresh the screen. If current has run off the top, this call
1230 * puts it at the center line. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001231 edit_redraw(current_save);
David Lawrence Ramseyb6aa4282004-03-14 01:42:17 +00001232
Chris Allegretta6232d662002-05-12 19:52:15 +00001233 return 0;
1234}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001235
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001236int do_mark(void)
1237{
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001238 TOGGLE(MARK_ISSET);
1239 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001240 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001241 mark_beginbuf = current;
1242 mark_beginx = current_x;
1243 } else {
1244 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001245 edit_refresh();
1246 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001247 return 1;
1248}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001249#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001250
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001251#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001252void wrap_reset(void)
1253{
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001254 same_line_wrap = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001255}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001256#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001257
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001258#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001259/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001260 * moved forward since the last typed character. Return value:
1261 * whether we wrapped. */
1262int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001263{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001264 size_t len = strlen(inptr->data); /* length of the line we wrap */
1265 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001266 int wrap_loc = -1; /* index of inptr->data where we wrap */
1267 int word_back = -1;
1268#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001269 const char *indentation = NULL;
1270 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001271 int indent_len = 0; /* strlen(indentation) */
1272#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001273 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001274 int after_break_len; /* strlen(after_break) */
1275 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001276 const char *wrap_line = NULL;
1277 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001278 int wrap_line_len = 0; /* strlen(wrap_line) */
1279 char *newline = NULL; /* the line we create */
1280 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001281
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001282/* There are three steps. First, we decide where to wrap. Then, we
1283 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001284
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001285/* Step 1, finding where to wrap. We are going to add a new-line
David Lawrence Ramsey89bb9372004-05-29 16:47:52 +00001286 * after a whitespace character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001287 * location of this replacement.
1288 *
1289 * Where should we break the line? We need the last "legal wrap point"
1290 * such that the last word before it ended at or before fill. If there
1291 * is no such point, we settle for the first legal wrap point.
1292 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001293 * A "legal wrap point" is a whitespace character that is not followed
1294 * by whitespace.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001295 *
1296 * If there is no legal wrap point or we found the last character of the
1297 * line, we should return without wrapping.
1298 *
1299 * Note that the initial indentation does not count as a legal wrap
1300 * point if we are going to auto-indent!
1301 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001302 * Note that the code below could be optimized, by not calling
1303 * strnlenpt() so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001304
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001305#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001306 if (ISSET(AUTOINDENT))
1307 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001308#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001309 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001310 for (; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001311 /* record where the last word ended */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001312 if (!isblank(*wrap_line))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001313 word_back = i;
1314 /* if we have found a "legal wrap point" and the current word
1315 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001316 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001317 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001318 /* we record the latest "legal wrap point" */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001319 if (word_back != i && !isblank(wrap_line[1]))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001320 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001321 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001322 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001323 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001324
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001325/* Step 2, making the new wrap line. It will consist of indentation +
1326 * after_break + " " + wrap_line (although indentation and wrap_line are
1327 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001328
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001329 /* after_break is the text that will be moved to the next line. */
1330 after_break = inptr->data + wrap_loc + 1;
1331 after_break_len = len - wrap_loc - 1;
1332 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001333
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001334 /* new_line_len will later be increased by the lengths of indentation
1335 * and wrap_line. */
1336 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001337
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001338 /* We prepend the wrapped text to the next line, if the flag is set,
1339 * and there is a next line, and prepending would not make the line
1340 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001341 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001342 wrap_line = inptr->next->data;
1343 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001344
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001345 /* +1 for the space between after_break and wrap_line */
1346 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1347 wrapping = 1;
1348 new_line_len += (1 + wrap_line_len);
1349 }
1350 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001351
Chris Allegrettaff989832001-09-17 13:48:00 +00001352#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001353 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001354 /* Indentation comes from the next line if wrapping, else from
1355 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001356 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001357 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001358 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001359 /* The wrap_line text should not duplicate indentation.
1360 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001361 wrap_line += indent_len;
1362 else
1363 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001364 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001365#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001366
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001367 /* Now we allocate the new line and copy into it. */
1368 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1369 *newline = '\0';
1370
1371#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001372 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001373 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001374 newline[indent_len] = '\0';
1375 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001376#endif
1377 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001378 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001379 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001380 null_at(&inptr->data, wrap_loc + 1);
1381 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001382 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001383 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001384 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001385 * in a tab or a space, we don't add a space and decrement
1386 * totsize to account for that. */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001387 if (!isblank(newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001388 strcat(newline, " ");
1389 else
1390 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001391 strcat(newline, wrap_line);
1392 free(inptr->next->data);
1393 inptr->next->data = newline;
1394 } else {
1395 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001396
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001397 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001398 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001399#ifndef NANO_SMALL
1400 totsize += indent_len;
1401#endif
1402 totlines++;
1403 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001404 temp->prev = inptr;
1405 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001406 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001407 /* If temp->next is NULL, then temp is the last line of the
1408 * file, so we must set filebot. */
1409 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001410 temp->next->prev = temp;
1411 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001412 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001413 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001414
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001415/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1416 * other sundry things. */
1417
1418 /* later wraps of this line will be prepended to the next line. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001419 same_line_wrap = 1;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001420
1421 /* Each line knows its line number. We recalculate these if we
1422 * inserted a new line. */
1423 if (!wrapping)
1424 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001425
Chris Allegretta6df90f52002-07-19 01:08:59 +00001426 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001427 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001428 current = current->next;
1429 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001430#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001431 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001432#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001433 wrap_loc + 1;
1434 wrap_reset();
1435 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001436 }
1437
Chris Allegretta6df90f52002-07-19 01:08:59 +00001438#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001439 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001440 * If it was on the next line and we wrapped, we must move it
1441 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001442 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1443 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001444 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001445 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001446 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001447#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001448
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001449 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001450 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001451
1452 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001453}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001454#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001455
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001456#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001457/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001458 * return zero if the user cancels. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001459int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001460{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001461 char *save_search;
1462 char *save_replace;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001463 size_t current_x_save = current_x;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001464 filestruct *current_save = current;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001465 filestruct *edittop_save = edittop;
1466 /* Save where we are. */
1467 int i = 0;
1468 /* The return value. */
1469 int reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001470#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001471 int case_sens_set = ISSET(CASE_SENSITIVE);
1472 int mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001473
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001474 SET(CASE_SENSITIVE);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001475 /* Make sure the marking highlight is off during spell-check. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001476 UNSET(MARK_ISSET);
1477#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001478 /* Make sure spell-check goes forward only. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001479 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001480
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001481 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001482 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001483 save_search = last_search;
1484 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001485
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001486 /* Set search/replace strings to misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001487 last_search = mallocstrcpy(NULL, word);
1488 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001489
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001490 /* Start from the top of the file. */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001491 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001492 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001493
1494 search_last_line = FALSE;
1495
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001496 /* Find the first whole-word occurrence of word. */
1497 while (findnextstr(TRUE, TRUE, fileage, 0, word, FALSE) != 0)
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001498 if (is_whole_word(current_x, current->data, word)) {
1499 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001500
Chris Allegretta6df90f52002-07-19 01:08:59 +00001501 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001502
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001503 /* Allow the replace word to be corrected. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001504 i = statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001505#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001506 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001507#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001508 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001509
Chris Allegretta6df90f52002-07-19 01:08:59 +00001510 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001511
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001512 if (i != -1 && strcmp(word, answer)) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001513 search_last_line = FALSE;
1514 current_x--;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001515 do_replace_loop(word, current_save, &current_x_save, TRUE);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001516 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001517
1518 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001519 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001520
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001521 /* Restore the search/replace strings. */
1522 free(last_search);
1523 last_search = save_search;
1524 free(last_replace);
1525 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001526
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001527 /* Restore where we were. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001528 current = current_save;
1529 current_x = current_x_save;
1530 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001531
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001532 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001533 if (reverse_search_set)
1534 SET(REVERSE_SEARCH);
1535
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001536#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001537 if (!case_sens_set)
1538 UNSET(CASE_SENSITIVE);
1539
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001540 /* Restore marking highlight. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001541 if (mark_set)
1542 SET(MARK_ISSET);
1543#endif
1544
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001545 return i != -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001546}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001547
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001548/* Integrated spell checking using 'spell' program. Return value: NULL
1549 * for normal termination, otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001550const char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001551{
Chris Allegretta271e9722000-11-10 18:15:43 +00001552 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001553 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001554 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001555 pid_t pid_spell, pid_sort, pid_uniq;
1556 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001557
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001558 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001559 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1560 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001561
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001562 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001563
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001564 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001565 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001566
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001567 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001568
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001569 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001570
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001571 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001572 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1573 goto close_pipes_and_exit;
1574
1575 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1576 goto close_pipes_and_exit;
1577
Chris Allegretta271e9722000-11-10 18:15:43 +00001578 close(tempfile_fd);
1579
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001580 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001581 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1582 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001583
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001584 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001585
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001586 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001587 execlp("spell", "spell", NULL);
1588
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001589 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001590 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001591 }
1592
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001593 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001594 close(spell_fd[1]);
1595
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001596 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001597 if ((pid_sort = fork()) == 0) {
1598
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001599 /* Child continues (i.e, future spell process). Replace the
1600 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001601 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1602 goto close_pipes_and_exit;
1603
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001604 close(spell_fd[0]);
1605
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001606 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001607 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1608 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001609
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001610 close(sort_fd[1]);
1611
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001612 /* Start sort program. Use -f to remove mixed case without
1613 * having to have ANOTHER pipe for tr. If this isn't portable,
1614 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001615 execlp("sort", "sort", "-f", NULL);
1616
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001617 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001618 exit(1);
1619 }
1620
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001621 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001622 close(sort_fd[1]);
1623
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001624 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001625 if ((pid_uniq = fork()) == 0) {
1626
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001627 /* Child continues (i.e, future uniq process). Replace the
1628 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001629 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1630 goto close_pipes_and_exit;
1631
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001632 close(sort_fd[0]);
1633
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001634 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001635 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1636 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001637
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001638 close(uniq_fd[1]);
1639
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001640 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001641 execlp("uniq", "uniq", NULL);
1642
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001643 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001644 exit(1);
1645 }
1646
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001647 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001648 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001649
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001650 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001651 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1652 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001653 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001654 }
1655
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001656 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001657 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1658 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001659 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001660 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001661
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001662 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001663 read_buff_read = 0;
1664 read_buff_size = pipe_buff_size + 1;
1665 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001666
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001667 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001668 read_buff_read += bytesread;
1669 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001670 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001671 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001672
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001673 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001674
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001675 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001676 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001677
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001678 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001679 read_buff_word = read_buff_ptr = read_buff;
1680
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001681 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001682
1683 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001684 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001685 if (read_buff_word != read_buff_ptr) {
1686 if (!do_int_spell_fix(read_buff_word)) {
1687 read_buff_word = read_buff_ptr;
1688 break;
1689 }
1690 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001691 read_buff_word = read_buff_ptr + 1;
1692 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001693 read_buff_ptr++;
1694 }
1695
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001696 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001697 if (read_buff_word != read_buff_ptr)
1698 do_int_spell_fix(read_buff_word);
1699
Chris Allegretta271e9722000-11-10 18:15:43 +00001700 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001701 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001702 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001703
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001704 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001705 waitpid(pid_spell, &spell_status, 0);
1706 waitpid(pid_sort, &sort_status, 0);
1707 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001708
Chris Allegretta334a9402002-12-16 04:25:53 +00001709 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1710 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001711
Chris Allegretta334a9402002-12-16 04:25:53 +00001712 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1713 return _("Error invoking \"sort -f\"");
1714
1715 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1716 return _("Error invoking \"uniq\"");
1717
1718 /* Otherwise... */
1719 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001720
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001721 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001722
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001723 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001724 close(tempfile_fd);
1725 close(spell_fd[0]);
1726 close(spell_fd[1]);
1727 close(sort_fd[0]);
1728 close(sort_fd[1]);
1729 close(uniq_fd[0]);
1730 close(uniq_fd[1]);
1731 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001732}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001733
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001734/* External spell checking. Return value: NULL for normal termination,
1735 * otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001736const char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001737{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001738 int alt_spell_status, lineno_cur = current->lineno;
1739 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001740 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001741 char *ptr;
1742 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001743 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001744#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001745 int mark_set = ISSET(MARK_ISSET);
1746 int mbb_lineno_cur = 0;
1747 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001748 * the alternate spell command. The line that mark_beginbuf
1749 * points to will be freed, so we save the line number and
1750 * restore afterwards. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001751
1752 if (mark_set) {
1753 mbb_lineno_cur = mark_beginbuf->lineno;
1754 UNSET(MARK_ISSET);
1755 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001756#endif
1757
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001758 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001759
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001760 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001761 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001762 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001763
Chris Allegrettae434b452001-01-27 19:25:00 +00001764 spellargs[0] = strtok(alt_speller, " ");
1765 while ((ptr = strtok(NULL, " ")) != NULL) {
1766 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001767 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001768 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001769 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001770 spellargs[arglen - 1] = NULL;
1771 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001772 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001773
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001774 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001775 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001776 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00001777 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001778
1779 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001780 exit(1);
1781 }
1782
1783 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001784 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001785 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001786
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001787 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001788 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001789
Chris Allegretta334a9402002-12-16 04:25:53 +00001790 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1791 char *altspell_error = NULL;
1792 char *invoke_error = _("Could not invoke \"%s\"");
1793 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1794
1795 altspell_error = charalloc(msglen);
1796 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1797 return altspell_error;
1798 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001799
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001800 refresh();
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001801#ifndef NANO_SMALL
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001802 if (!mark_set) {
1803 /* Only reload the temp file if it isn't a marked selection. */
1804#endif
1805 free_filestruct(fileage);
1806 global_init(1);
1807 open_file(tempfile_name, 0, 1);
1808#ifndef NANO_SMALL
1809 }
1810
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001811 if (mark_set) {
1812 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1813 mark_beginbuf = current;
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001814 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001815 mark_beginx = current_x;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001816 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001817 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001818#endif
1819
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001820 /* Go back to the old position, mark the file as modified, and make
1821 * sure that the titlebar is refreshed. */
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001822 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001823 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001824 clearok(topwin, FALSE);
1825 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001826
Chris Allegretta334a9402002-12-16 04:25:53 +00001827 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001828}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001829
1830int do_spell(void)
1831{
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001832 int i;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001833 char *temp = safe_tempnam(0, "nano.");
1834 const char *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001835
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001836 if (temp == NULL) {
1837 statusbar(_("Could not create temp file: %s"), strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001838 return 0;
1839 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001840
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001841#ifndef NANO_SMALL
1842 if (ISSET(MARK_ISSET))
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001843 i = write_marked(temp, TRUE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001844 else
1845#endif
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001846 i = write_file(temp, TRUE, FALSE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001847
1848 if (i == -1) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001849 statusbar(_("Unable to write temp file: %s"), strerror(errno));
Chris Allegrettabef12972002-03-06 03:30:40 +00001850 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001851 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001852 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001853
Chris Allegrettae1f14522001-09-19 03:19:43 +00001854#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001855 /* Update the current open_files entry before spell-checking, in
1856 * case any problems occur. */
Chris Allegretta48b06702002-02-22 04:30:50 +00001857 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001858#endif
1859
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001860 spell_msg = alt_speller != NULL ? do_alt_speller(temp) :
1861 do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001862 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001863 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001864
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001865 if (spell_msg != NULL) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001866 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
1867 strerror(errno));
Chris Allegretta334a9402002-12-16 04:25:53 +00001868 return 0;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001869 } else
1870 statusbar(_("Finished checking spelling"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001871
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001872 return 1;
Chris Allegretta67105eb2000-07-03 03:18:32 +00001873}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001874#endif /* !DISABLE_SPELLER */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001875
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001876#if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001877/* The "indentation" of a line is the whitespace between the quote part
1878 * and the non-whitespace of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001879size_t indent_length(const char *line)
1880{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001881 size_t len = 0;
1882
1883 assert(line != NULL);
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001884 while (isblank(*line)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001885 line++;
1886 len++;
1887 }
1888 return len;
1889}
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001890#endif /* !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001891
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001892#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001893/* justify_format() replaces Tab by Space and multiple spaces by 1
1894 * (except it maintains 2 after a . ! or ?). Note the terminating \0
Chris Allegretta6df90f52002-07-19 01:08:59 +00001895 * counts as a space.
1896 *
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001897 * justify_format() might make line->data shorter, and change the actual
1898 * pointer with null_at().
Chris Allegretta6df90f52002-07-19 01:08:59 +00001899 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001900 * justify_format() will not look at the first skip characters of line.
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001901 * skip should be at most strlen(line->data). The character at
1902 * line[skip + 1] must not be whitespace. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001903void justify_format(filestruct *line, size_t skip)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001904{
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
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00002961#ifdef ENABLE_NANORC
2962 case TOGGLE_WHITESPACE_KEY:
2963 edit_refresh();
2964 break;
2965#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002966 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002967
Chris Allegretta6df90f52002-07-19 01:08:59 +00002968 /* We are assuming here that shortcut_init() above didn't free and
2969 * reallocate the toggles. */
2970 enabled = ISSET(which->flag);
2971 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2972 enabled = !enabled;
2973 statusbar("%s %s", which->desc,
2974 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002975}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002976#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002977
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002978void disable_signals(void)
2979{
2980 struct termios term;
2981
2982 tcgetattr(0, &term);
2983 term.c_lflag &= ~ISIG;
2984 tcsetattr(0, TCSANOW, &term);
2985}
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002986
2987#ifndef NANO_SMALL
2988void enable_signals(void)
2989{
2990 struct termios term;
2991
2992 tcgetattr(0, &term);
2993 term.c_lflag |= ISIG;
2994 tcsetattr(0, TCSANOW, &term);
2995}
2996#endif
2997
2998void disable_flow_control(void)
2999{
3000 struct termios term;
3001
3002 tcgetattr(0, &term);
3003 term.c_iflag &= ~(IXON|IXOFF);
3004 tcsetattr(0, TCSANOW, &term);
3005}
3006
3007void enable_flow_control(void)
3008{
3009 struct termios term;
3010
3011 tcgetattr(0, &term);
3012 term.c_iflag |= (IXON|IXOFF);
3013 tcsetattr(0, TCSANOW, &term);
3014}
3015
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003016int main(int argc, char *argv[])
3017{
3018 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003019 int startline = 0; /* Line to try and start at */
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003020 int modify_control_seq = 0;
Chris Allegretta09fc4302003-01-16 22:16:38 +00003021 int fill_flag_used = 0; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003022 const shortcut *s;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003023 int keyhandled = 0; /* Have we handled the keystroke yet? */
David Lawrence Ramseyf8ddf312004-01-09 22:38:09 +00003024 int kbinput; /* Input from keyboard */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003025 int meta_key;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003026
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003027#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003028 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003029#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003030#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003031 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003032 {"help", 0, 0, 'h'},
3033#ifdef ENABLE_MULTIBUFFER
3034 {"multibuffer", 0, 0, 'F'},
3035#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003036#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003037#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003038 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003039#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003040 {"ignorercfiles", 0, 0, 'I'},
3041#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003042#ifndef DISABLE_JUSTIFY
3043 {"quotestr", 1, 0, 'Q'},
3044#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003045#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003046 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003047#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003048 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003049 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003050#ifdef ENABLE_COLOR
3051 {"syntax", 1, 0, 'Y'},
3052#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003053 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003054 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003055 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003056#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003057 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003058#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003059#ifndef DISABLE_OPERATINGDIR
3060 {"operatingdir", 1, 0, 'o'},
3061#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003062 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003063#ifndef DISABLE_WRAPJUSTIFY
3064 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003065#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003066#ifndef DISABLE_SPELLER
3067 {"speller", 1, 0, 's'},
3068#endif
3069 {"tempfile", 0, 0, 't'},
3070 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003071#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003072 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003073#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003074 {"nohelp", 0, 0, 'x'},
3075 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003076#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003077 {"smarthome", 0, 0, 'A'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003078 {"backup", 0, 0, 'B'},
3079 {"dos", 0, 0, 'D'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003080 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003081 {"mac", 0, 0, 'M'},
3082 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003083 {"smooth", 0, 0, 'S'},
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003084 {"restricted", 0, 0, 'Z'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003085 {"autoindent", 0, 0, 'i'},
3086 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003087#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003088 {0, 0, 0, 0}
3089 };
3090#endif
3091
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003092#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003093 setlocale(LC_ALL, "");
3094 bindtextdomain(PACKAGE, LOCALEDIR);
3095 textdomain(PACKAGE);
3096#endif
3097
Chris Allegretta7662c862003-01-13 01:35:15 +00003098#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003099 /* if we don't have rcfile support, we're root, and
3100 --disable-wrapping-as-root is used, turn wrapping off */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003101 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003102 SET(NO_WRAP);
3103#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003104
3105#ifdef HAVE_GETOPT_LONG
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003106 while ((optchr = getopt_long(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz",
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003107 long_options, NULL)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003108#else
3109 while ((optchr =
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003110 getopt(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003111#endif
3112
3113 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003114
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003115 case 'a':
3116 case 'b':
3117 case 'e':
3118 case 'f':
3119 case 'g':
3120 case 'j':
3121 /* Pico compatibility flags */
3122 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003123#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003124 case 'A':
3125 SET(SMART_HOME);
3126 break;
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003127 case 'B':
3128 SET(BACKUP_FILE);
3129 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003130 case 'D':
3131 SET(DOS_FILE);
3132 break;
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003133 case 'E':
3134 backup_dir = mallocstrcpy(backup_dir, optarg);
3135 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003136#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003137#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003138 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003139 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003140 break;
3141#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003142#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003143#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003144 case 'H':
3145 SET(HISTORYLOG);
3146 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003147#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003148 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003149 SET(NO_RCFILE);
3150 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003151#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003152#ifndef NANO_SMALL
3153 case 'M':
3154 SET(MAC_FILE);
3155 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003156 case 'N':
3157 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003158 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003159#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003160#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003161 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003162 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003163 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003164#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003165#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003166 case 'R':
3167 SET(USE_REGEXP);
3168 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003169#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003170#ifndef NANO_SMALL
3171 case 'S':
3172 SET(SMOOTHSCROLL);
3173 break;
3174#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003175 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003176 {
3177 int i;
3178 char *first_error;
3179
Chris Allegretta7662c862003-01-13 01:35:15 +00003180 /* Using strtol() instead of atoi() lets us accept 0
3181 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003182 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003183 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003184 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003185 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003186 tabsize = i;
3187 if (tabsize <= 0) {
3188 fprintf(stderr, _("Tab size is too small for nano...\n"));
3189 exit(1);
3190 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003191 }
3192 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003193 case 'V':
3194 version();
3195 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003196#ifdef ENABLE_COLOR
3197 case 'Y':
3198 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3199 break;
3200#endif
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003201 case 'Z':
3202 SET(RESTRICTED);
3203 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003204 case 'c':
3205 SET(CONSTUPDATE);
3206 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003207 case 'd':
3208 SET(REBIND_DELETE);
3209 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003210#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003211 case 'i':
3212 SET(AUTOINDENT);
3213 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003214 case 'k':
3215 SET(CUT_TO_END);
3216 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003217#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003218 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003219 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003220 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003221#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003222 case 'm':
3223 SET(USE_MOUSE);
3224 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003225#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003226#ifndef DISABLE_OPERATINGDIR
3227 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003228 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003229 break;
3230#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003231 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003232 SET(PRESERVE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003233 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003234#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003235 case 'r':
3236 {
3237 int i;
3238 char *first_error;
3239
Chris Allegretta7662c862003-01-13 01:35:15 +00003240 /* Using strtol() instead of atoi() lets us accept 0
3241 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003242 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003243 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003244 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003245 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003246 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003247 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003248 fill_flag_used = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003249 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003250#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003251#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003252 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003253 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003254 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003255#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003256 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003257 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003258 break;
3259 case 'v':
3260 SET(VIEW_MODE);
3261 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003262#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003263 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003264 SET(NO_WRAP);
3265 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003266#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003267 case 'x':
3268 SET(NO_HELP);
3269 break;
3270 case 'z':
3271 SET(SUSPEND);
3272 break;
3273 default:
3274 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003275 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003276 }
3277
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003278 /* If the executable filename starts with 'r', we use restricted
3279 * mode. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003280 if (*(tail(argv[0])) == 'r')
3281 SET(RESTRICTED);
3282
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003283 /* If we're using restricted mode, disable suspending, backups, and
3284 * reading rcfiles, since they all would allow reading from or
3285 * writing to files not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003286 if (ISSET(RESTRICTED)) {
3287 UNSET(SUSPEND);
3288 UNSET(BACKUP_FILE);
3289 SET(NO_RCFILE);
3290 }
3291
Chris Allegretta7662c862003-01-13 01:35:15 +00003292/* We've read through the command line options. Now back up the flags
3293 and values that are set, and read the rcfile(s). If the values
3294 haven't changed afterward, restore the backed-up values. */
3295#ifdef ENABLE_NANORC
3296 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003297#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003298 char *operating_dir_cpy = operating_dir;
3299#endif
3300#ifndef DISABLE_WRAPPING
3301 int wrap_at_cpy = wrap_at;
3302#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003303#ifndef NANO_SMALL
3304 char *backup_dir_cpy = backup_dir;
3305#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003306#ifndef DISABLE_JUSTIFY
3307 char *quotestr_cpy = quotestr;
3308#endif
3309#ifndef DISABLE_SPELLER
3310 char *alt_speller_cpy = alt_speller;
3311#endif
3312 int tabsize_cpy = tabsize;
3313 long flags_cpy = flags;
3314
Chris Allegretta5ec68622003-02-05 02:39:34 +00003315#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003316 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003317#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003318#ifndef NANO_SMALL
3319 backup_dir = NULL;
3320#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003321#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003322 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003323#endif
3324#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003325 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003326#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003327
3328 do_rcfile();
3329
3330#ifndef DISABLE_OPERATINGDIR
3331 if (operating_dir_cpy != NULL) {
3332 free(operating_dir);
3333 operating_dir = operating_dir_cpy;
3334 }
3335#endif
3336#ifndef DISABLE_WRAPPING
3337 if (fill_flag_used)
3338 wrap_at = wrap_at_cpy;
3339#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003340#ifndef NANO_SMALL
3341 if (backup_dir_cpy != NULL) {
3342 free(backup_dir);
3343 backup_dir = backup_dir_cpy;
3344 }
3345#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003346#ifndef DISABLE_JUSTIFY
3347 if (quotestr_cpy != NULL) {
3348 free(quotestr);
3349 quotestr = quotestr_cpy;
3350 }
3351#endif
3352#ifndef DISABLE_SPELLER
3353 if (alt_speller_cpy != NULL) {
3354 free(alt_speller);
3355 alt_speller = alt_speller_cpy;
3356 }
3357#endif
3358 if (tabsize_cpy > 0)
3359 tabsize = tabsize_cpy;
3360 flags |= flags_cpy;
3361 }
3362#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003363 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003364 SET(NO_WRAP);
3365#endif
3366#endif /* ENABLE_NANORC */
3367
Chris Allegrettad8451932003-03-11 03:50:40 +00003368#ifndef NANO_SMALL
3369 history_init();
3370#ifdef ENABLE_NANORC
3371 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3372 load_history();
3373#endif
3374#endif
3375
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003376#ifndef NANO_SMALL
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003377 /* Set up the backup directory (unless we're using restricted mode,
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003378 * in which case backups are disabled, since they would allow
3379 * reading from or writing to files not specified on the command
3380 * line). This entails making sure it exists and is a directory, so
3381 * that backup files will be saved there. */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003382 if (!ISSET(RESTRICTED))
3383 init_backup_dir();
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003384#endif
3385
Chris Allegretta7662c862003-01-13 01:35:15 +00003386#ifndef DISABLE_OPERATINGDIR
3387 /* Set up the operating directory. This entails chdir()ing there,
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003388 * so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003389 init_operating_dir();
3390#endif
3391
Chris Allegretta7662c862003-01-13 01:35:15 +00003392#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003393 if (punct == NULL)
3394 punct = mallocstrcpy(punct, ".?!");
3395
3396 if (brackets == NULL)
3397 brackets = mallocstrcpy(brackets, "'\")}]>");
3398
Chris Allegretta7662c862003-01-13 01:35:15 +00003399 if (quotestr == NULL)
3400#ifdef HAVE_REGEX_H
3401 quotestr = mallocstrcpy(NULL, "^([ \t]*[|>:}#])+");
3402#else
3403 quotestr = mallocstrcpy(NULL, "> ");
3404#endif
3405#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003406
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003407#ifndef DISABLE_SPELLER
3408 /* If we don't have an alternative spell checker after reading the
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003409 * command line and/or rcfile(s), check $SPELL for one, as Pico
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003410 * does (unless we're using restricted mode, in which case spell
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003411 * checking is disabled, since it would allow reading from or
3412 * writing to files not specified on the command line). */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003413 if (!ISSET(RESTRICTED) && alt_speller == NULL) {
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003414 char *spellenv = getenv("SPELL");
3415 if (spellenv != NULL)
3416 alt_speller = mallocstrcpy(NULL, spellenv);
3417 }
3418#endif
3419
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003420#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
3421 if (whitespace == NULL)
3422 whitespace = mallocstrcpy(NULL, " ");
3423#endif
3424
Chris Allegretta7662c862003-01-13 01:35:15 +00003425 if (tabsize == -1)
3426 tabsize = 8;
3427
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003428 /* Clear the filename we'll be using */
3429 filename = charalloc(1);
3430 filename[0] = '\0';
3431
Chris Allegretta7662c862003-01-13 01:35:15 +00003432 /* If there's a +LINE flag, it is the first non-option argument. */
3433 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3434 startline = atoi(&argv[optind][1]);
3435 optind++;
3436 }
3437 if (0 < optind && optind < argc)
3438 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003439
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003440 /* See if there's a non-option in argv (first non-option is the
3441 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003442 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003443 /* Look for the +line flag... */
3444 if (argv[optind][0] == '+') {
3445 startline = atoi(&argv[optind][1]);
3446 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003447 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003448 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003449 } else
3450 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003451 }
3452
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003453 /* Back up the old terminal settings so that they can be restored. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003454 tcgetattr(0, &oldterm);
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003455
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003456 /* Curses initialization stuff: Start curses, save the state of the
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003457 * terminal mode, put the terminal in cbreak mode (read one character
3458 * at a time and interpret the special control keys), disable
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003459 * translation of carriage return (^M) into newline (^J) so that we
David Lawrence Ramseyfd462b12004-05-19 15:41:17 +00003460 * can tell the difference between the Enter key and Ctrl-J, and
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003461 * disable echoing of characters as they're typed. Finally, disable
3462 * interpretation of the special control keys, and if we're not in
3463 * preserve mode, disable interpretation of the flow control
3464 * characters too. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003465 initscr();
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003466 cbreak();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003467 nonl();
David Lawrence Ramseyd03216a2004-01-28 18:21:21 +00003468 noecho();
David Lawrence Ramseye608f942004-05-19 16:04:27 +00003469 disable_signals();
3470 if (!ISSET(PRESERVE))
3471 disable_flow_control();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003472
3473#ifndef NANO_SMALL
3474 /* Save the terminal's current state, so that we can restore it
3475 * after a resize. */
3476 savetty();
3477#endif
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003478
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003479 /* Set up the global variables and the shortcuts. */
Chris Allegretta56214c62001-09-27 02:46:53 +00003480 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003481 shortcut_init(0);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003482
3483 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003484 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003485
3486#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003487 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003488#endif
3489
Chris Allegretta2a42af12000-09-12 23:02:49 +00003490 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003491#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003492 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003493#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003494
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003495#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003496 fprintf(stderr, "Main: bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003497#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003498 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003499 display_main_list();
3500
3501#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003502 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003503#endif
3504
David Lawrence Ramsey97133f52004-05-14 17:39:19 +00003505 open_file(filename, 0, 0);
Chris Allegretta7662c862003-01-13 01:35:15 +00003506#ifdef ENABLE_MULTIBUFFER
3507 /* If we're using multibuffers and more than one file is specified
3508 on the command line, load them all and switch to the first one
3509 afterward */
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003510 if (optind + 1 < argc) {
3511 int old_multibuffer = ISSET(MULTIBUFFER);
3512 SET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003513 for (optind++; optind < argc; optind++) {
3514 add_open_file(1);
3515 new_file();
3516 filename = mallocstrcpy(filename, argv[optind]);
3517 open_file(filename, 0, 0);
3518 load_file(0);
3519 }
3520 open_nextfile_void();
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003521 if (!old_multibuffer)
3522 UNSET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003523 }
3524#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003525
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003526 titlebar(NULL);
3527
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003528 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003529 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003530
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003531#ifndef NANO_SMALL
3532 /* Return here after a SIGWINCH. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003533 sigsetjmp(jmpbuf, 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003534#endif
Chris Allegretta08020882001-01-29 23:37:54 +00003535
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003536 /* SHUT UP GCC! */
3537 startline = 0;
3538 fill_flag_used = 0;
3539 keyhandled = 0;
3540
Chris Allegretta7662c862003-01-13 01:35:15 +00003541 /* This variable should be initialized after the sigsetjmp(), so we
3542 can't do Esc-Esc then quickly resize and muck things up. */
Chris Allegretta08020882001-01-29 23:37:54 +00003543 modify_control_seq = 0;
3544
Robert Siemborski6967eec2000-07-08 14:23:32 +00003545 edit_refresh();
3546 reset_cursor();
3547
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003548 while (TRUE) {
Chris Allegrettad0845df2003-02-13 00:56:57 +00003549 keyhandled = 0;
Chris Allegretta9239d742000-09-06 15:19:18 +00003550
Chris Allegrettad26ab912003-01-28 01:16:47 +00003551 if (ISSET(CONSTUPDATE))
3552 do_cursorpos(1);
3553
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003554#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003555 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003556#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003557
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003558 kbinput = get_kbinput(edit, &meta_key);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003559#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003560 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003561#endif
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003562 if (meta_key == TRUE) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003563 /* Check for the metaval and miscval defs... */
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003564 for (s = main_list; s != NULL; s = s->next)
David Lawrence Ramsey82138502003-12-24 08:03:54 +00003565 if ((s->metaval != NANO_NO_KEY && kbinput == s->metaval) ||
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003566 (s->miscval != NANO_NO_KEY && kbinput == s->miscval)) {
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003567 if (ISSET(VIEW_MODE) && !s->viewok)
3568 print_view_warning();
3569 else {
3570 if (s->func != do_cut_text)
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003571 cutbuffer_reset();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003572 s->func();
3573 }
3574 keyhandled = 1;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003575 }
3576#ifndef NANO_SMALL
3577 if (!keyhandled)
3578 /* And for toggle switches */
3579 for (t = toggles; t != NULL; t = t->next)
3580 if (kbinput == t->val) {
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003581 cutbuffer_reset();
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003582 do_toggle(t);
3583 keyhandled = 1;
3584 }
3585#endif
3586#ifdef DEBUG
3587 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput,
3588 kbinput);
3589#endif
3590 }
3591
3592 /* Look through the main shortcut list to see if we've hit a
3593 shortcut key or function key */
3594
3595 if (!keyhandled)
3596#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
3597 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
3598#else
3599 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
3600#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003601 if ((s->ctrlval != NANO_NO_KEY && kbinput == s->ctrlval) ||
3602 (s->funcval != NANO_NO_KEY && kbinput == s->funcval)) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003603 if (ISSET(VIEW_MODE) && !s->viewok)
3604 print_view_warning();
3605 else {
3606 if (s->func != do_cut_text)
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003607 cutbuffer_reset();
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003608 s->func();
3609 }
3610 keyhandled = 1;
3611 /* Break out explicitly once we successfully handle
3612 a shortcut */
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003613 break;
3614 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003615 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003616
3617 if (!keyhandled)
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003618 cutbuffer_reset();
Chris Allegrettae42df732002-10-15 00:27:55 +00003619
Chris Allegrettae42df732002-10-15 00:27:55 +00003620 /* Don't even think about changing this string */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003621 if (kbinput == NANO_CONTROL_Q)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003622 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003623 if (kbinput == NANO_CONTROL_S)
3624 statusbar(_("XOFF ignored, mumble mumble."));
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003625
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003626 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3627 Control-S and Control-Q */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003628 if (kbinput == NANO_CONTROL_Q || kbinput == NANO_CONTROL_S)
Chris Allegretta9239d742000-09-06 15:19:18 +00003629 keyhandled = 1;
3630
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003631 /* Catch ^Z by hand when triggered also */
3632 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003633 if (ISSET(SUSPEND))
3634 do_suspend(0);
3635 keyhandled = 1;
3636 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003637
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003638 /* Last gasp, stuff that's not in the main lists */
3639 if (!keyhandled)
3640 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003641#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003642 case KEY_MOUSE:
3643 do_mouse();
3644 break;
3645#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003646
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003647 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3648 * have been handled before we
3649 * got here */
3650 case NANO_CONTROL_5: /* Ctrl-] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003651 break;
3652 default:
3653#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003654 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003655#endif
3656 /* We no longer stop unhandled sequences so that people with
3657 odd character sets can type... */
3658
Chris Allegretta7662c862003-01-13 01:35:15 +00003659 if (ISSET(VIEW_MODE))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003660 print_view_warning();
Chris Allegretta7662c862003-01-13 01:35:15 +00003661 else
David Lawrence Ramsey570ea892004-05-28 21:02:32 +00003662 do_char((char)kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003663 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003664
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003665 reset_cursor();
3666 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003667 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003668 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003669}