blob: 4578bb4165ad1c70d20f6ad67afde3eacaf1224d [file] [log] [blame]
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001/* $Id$ */
2/**************************************************************************
David Lawrence Ramsey4005fc62005-10-08 06:12:41 +00003 * text.c *
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00004 * *
David Lawrence Ramseyd8a1d372007-10-11 05:01:32 +00005 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 *
6 * Free Software Foundation, Inc. *
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00007 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
David Lawrence Ramseyd0035b42007-08-11 05:17:36 +00009 * the Free Software Foundation; either version 3, or (at your option) *
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000010 * any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, but *
13 * WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
15 * General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
20 * 02110-1301, USA. *
21 * *
22 **************************************************************************/
23
David Lawrence Ramsey034b9942005-12-08 02:47:10 +000024#include "proto.h"
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000025
David Lawrence Ramseyee11c6a2005-11-02 19:42:02 +000026#include <stdio.h>
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000027#include <signal.h>
28#include <unistd.h>
29#include <string.h>
30#include <fcntl.h>
31#include <sys/wait.h>
32#include <errno.h>
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000033
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000034#ifndef NANO_TINY
David Lawrence Ramsey8779a172005-11-08 16:45:22 +000035static pid_t pid = -1;
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +000036 /* The PID of the forked process in execute_command(), for use
37 * with the cancel_command() signal handler. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000038#endif
39#ifndef DISABLE_WRAPPING
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +000040static bool prepend_wrap = FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000041 /* Should we prepend wrapped text to the next line? */
42#endif
43#ifndef DISABLE_JUSTIFY
44static filestruct *jusbottom = NULL;
David Lawrence Ramseyae4c3a62005-09-20 19:46:39 +000045 /* Pointer to the end of the justify buffer. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000046#endif
47
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000048#ifndef NANO_TINY
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +000049/* Toggle the mark. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000050void do_mark(void)
51{
52 openfile->mark_set = !openfile->mark_set;
53 if (openfile->mark_set) {
54 statusbar(_("Mark Set"));
55 openfile->mark_begin = openfile->current;
56 openfile->mark_begin_x = openfile->current_x;
57 } else {
David Lawrence Ramsey7b0531a2006-07-31 01:30:31 +000058 statusbar(_("Mark Unset"));
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000059 openfile->mark_begin = NULL;
60 openfile->mark_begin_x = 0;
61 edit_refresh();
62 }
63}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000064#endif /* !NANO_TINY */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000065
David Lawrence Ramseyf1982f02006-12-10 17:57:09 +000066/* Delete the character under the cursor. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000067void do_delete(void)
68{
69 bool do_refresh = FALSE;
70 /* Do we have to call edit_refresh(), or can we get away with
David Lawrence Ramsey75e9dfe2006-05-18 17:50:08 +000071 * just update_line()? */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000072
73 assert(openfile->current != NULL && openfile->current->data != NULL && openfile->current_x <= strlen(openfile->current->data));
74
75 openfile->placewewant = xplustabs();
76
77 if (openfile->current->data[openfile->current_x] != '\0') {
78 int char_buf_len = parse_mbchar(openfile->current->data +
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +000079 openfile->current_x, NULL, NULL);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000080 size_t line_len = strlen(openfile->current->data +
81 openfile->current_x);
82
83 assert(openfile->current_x < strlen(openfile->current->data));
84
85 /* Let's get dangerous. */
86 charmove(&openfile->current->data[openfile->current_x],
87 &openfile->current->data[openfile->current_x +
88 char_buf_len], line_len - char_buf_len + 1);
89
90 null_at(&openfile->current->data, openfile->current_x +
91 line_len - char_buf_len);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000092#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000093 if (openfile->mark_set && openfile->mark_begin ==
94 openfile->current && openfile->current_x <
95 openfile->mark_begin_x)
96 openfile->mark_begin_x -= char_buf_len;
97#endif
98 openfile->totsize--;
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +000099 } else if (openfile->current != openfile->filebot) {
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000100 filestruct *foo = openfile->current->next;
101
102 assert(openfile->current_x == strlen(openfile->current->data));
103
104 /* If we're deleting at the end of a line, we need to call
105 * edit_refresh(). */
106 if (openfile->current->data[openfile->current_x] == '\0')
107 do_refresh = TRUE;
108
109 openfile->current->data = charealloc(openfile->current->data,
110 openfile->current_x + strlen(foo->data) + 1);
111 strcpy(openfile->current->data + openfile->current_x,
112 foo->data);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000113#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000114 if (openfile->mark_set && openfile->mark_begin ==
115 openfile->current->next) {
116 openfile->mark_begin = openfile->current;
117 openfile->mark_begin_x += openfile->current_x;
118 }
119#endif
120 if (openfile->filebot == foo)
121 openfile->filebot = openfile->current;
122
123 unlink_node(foo);
124 delete_node(foo);
125 renumber(openfile->current);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000126 openfile->totsize--;
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000127
David Lawrence Ramseya0168ca2005-11-05 17:35:44 +0000128 /* If the NO_NEWLINES flag isn't set, and text has been added to
129 * the magicline as a result of deleting at the end of the line
David Lawrence Ramsey0f6236f2005-11-09 00:08:29 +0000130 * before filebot, add a new magicline. */
David Lawrence Ramseya0168ca2005-11-05 17:35:44 +0000131 if (!ISSET(NO_NEWLINES) && openfile->current ==
132 openfile->filebot && openfile->current->data[0] != '\0')
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000133 new_magicline();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000134 } else
135 return;
136
David Lawrence Ramsey0f6236f2005-11-09 00:08:29 +0000137 set_modified();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000138
139#ifdef ENABLE_COLOR
140 /* If color syntaxes are available and turned on, we need to call
141 * edit_refresh(). */
142 if (openfile->colorstrings != NULL && !ISSET(NO_COLOR_SYNTAX))
143 do_refresh = TRUE;
144#endif
145
146 if (do_refresh)
147 edit_refresh();
148 else
149 update_line(openfile->current, openfile->current_x);
150}
151
David Lawrence Ramsey5b7b3e32005-12-31 21:22:54 +0000152/* Backspace over one character. That is, move the cursor left one
David Lawrence Ramsey84d22e32006-11-08 13:05:50 +0000153 * character, and then delete the character under the cursor. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000154void do_backspace(void)
155{
156 if (openfile->current != openfile->fileage ||
157 openfile->current_x > 0) {
David Lawrence Ramsey1c3bfa92005-09-13 04:53:44 +0000158 do_left();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000159 do_delete();
160 }
161}
162
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000163/* Insert a tab. If the TABS_TO_SPACES flag is set, insert the number
164 * of spaces that a tab would normally take up. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000165void do_tab(void)
166{
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000167#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000168 if (ISSET(TABS_TO_SPACES)) {
169 char *output;
David Lawrence Ramsey90b07fc2005-10-07 15:57:48 +0000170 size_t output_len = 0, new_pww = xplustabs();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000171
172 do {
173 new_pww++;
174 output_len++;
175 } while (new_pww % tabsize != 0);
176
177 output = charalloc(output_len + 1);
178
179 charset(output, ' ', output_len);
180 output[output_len] = '\0';
181
182 do_output(output, output_len, TRUE);
183
184 free(output);
185 } else {
186#endif
187 do_output("\t", 1, TRUE);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000188#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000189 }
190#endif
191}
192
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000193#ifndef NANO_TINY
David Lawrence Ramseye44cd2d2007-01-11 22:54:55 +0000194/* Indent or unindent the current line (or, if the mark is on, all lines
195 * covered by the mark) len columns, depending on whether len is
196 * positive or negative. If the TABS_TO_SPACES flag is set, indent or
197 * unindent by len spaces. Otherwise, indent or unindent by (len /
198 * tabsize) tabs and (len % tabsize) spaces. */
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000199void do_indent(ssize_t cols)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000200{
201 bool indent_changed = FALSE;
202 /* Whether any indenting or unindenting was done. */
203 bool unindent = FALSE;
204 /* Whether we're unindenting text. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000205 char *line_indent = NULL;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000206 /* The text added to each line in order to indent it. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000207 size_t line_indent_len = 0;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000208 /* The length of the text added to each line in order to indent
209 * it. */
210 filestruct *top, *bot, *f;
211 size_t top_x, bot_x;
212
213 assert(openfile->current != NULL && openfile->current->data != NULL);
214
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000215 /* If cols is zero, get out. */
216 if (cols == 0)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000217 return;
218
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000219 /* If cols is negative, make it positive and set unindent to
220 * TRUE. */
221 if (cols < 0) {
222 cols = -cols;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000223 unindent = TRUE;
224 /* Otherwise, we're indenting, in which case the file will always be
225 * modified, so set indent_changed to TRUE. */
226 } else
227 indent_changed = TRUE;
228
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000229 /* If the mark is on, use all lines covered by the mark. */
230 if (openfile->mark_set)
231 mark_order((const filestruct **)&top, &top_x,
232 (const filestruct **)&bot, &bot_x, NULL);
233 /* Otherwise, use the current line. */
234 else {
235 top = openfile->current;
236 bot = top;
237 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000238
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000239 if (!unindent) {
240 /* Set up the text we'll be using as indentation. */
241 line_indent = charalloc(cols + 1);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000242
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000243 if (ISSET(TABS_TO_SPACES)) {
244 /* Set the indentation to cols spaces. */
245 charset(line_indent, ' ', cols);
246 line_indent_len = cols;
247 } else {
248 /* Set the indentation to (cols / tabsize) tabs and (cols %
249 * tabsize) spaces. */
250 size_t num_tabs = cols / tabsize;
251 size_t num_spaces = cols % tabsize;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000252
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000253 charset(line_indent, '\t', num_tabs);
254 charset(line_indent + num_tabs, ' ', num_spaces);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000255
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000256 line_indent_len = num_tabs + num_spaces;
257 }
258
259 line_indent[line_indent_len] = '\0';
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000260 }
261
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000262 /* Go through each line of the text. */
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000263 for (f = top; f != bot->next; f = f->next) {
264 size_t line_len = strlen(f->data);
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000265 size_t indent_len = indent_length(f->data);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000266
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000267 if (!unindent) {
268 /* If we're indenting, add the characters in line_indent to
269 * the beginning of the non-whitespace text of this line. */
270 f->data = charealloc(f->data, line_len +
271 line_indent_len + 1);
272 charmove(&f->data[indent_len + line_indent_len],
273 &f->data[indent_len], line_len - indent_len + 1);
274 strncpy(f->data + indent_len, line_indent, line_indent_len);
275 openfile->totsize += line_indent_len;
276
277 /* Keep track of the change in the current line. */
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000278 if (openfile->mark_set && f == openfile->mark_begin &&
279 openfile->mark_begin_x >= indent_len)
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000280 openfile->mark_begin_x += line_indent_len;
281
282 if (f == openfile->current && openfile->current_x >=
283 indent_len)
284 openfile->current_x += line_indent_len;
285
286 /* If the NO_NEWLINES flag isn't set, and this is the
287 * magicline, add a new magicline. */
288 if (!ISSET(NO_NEWLINES) && f == openfile->filebot)
289 new_magicline();
290 } else {
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000291 size_t indent_col = strnlenpt(f->data, indent_len);
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000292 /* The length in columns of the indentation on this
293 * line. */
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000294
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000295 if (cols <= indent_col) {
296 size_t indent_new = actual_x(f->data, indent_col -
297 cols);
David Lawrence Ramsey5bb77272006-05-06 14:37:33 +0000298 /* The length of the indentation remaining on
299 * this line after we unindent. */
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000300 size_t indent_shift = indent_len - indent_new;
David Lawrence Ramsey5bb77272006-05-06 14:37:33 +0000301 /* The change in the indentation on this line
302 * after we unindent. */
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000303
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000304 /* If we're unindenting, and there's at least cols
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000305 * columns' worth of indentation at the beginning of the
306 * non-whitespace text of this line, remove it. */
307 charmove(&f->data[indent_new], &f->data[indent_len],
308 line_len - indent_shift - indent_new + 1);
309 null_at(&f->data, line_len - indent_shift + 1);
310 openfile->totsize -= indent_shift;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000311
David Lawrence Ramsey2e8fac62006-04-29 15:44:58 +0000312 /* Keep track of the change in the current line. */
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000313 if (openfile->mark_set && f == openfile->mark_begin &&
David Lawrence Ramseyeb4f90e2006-05-05 14:22:42 +0000314 openfile->mark_begin_x > indent_new) {
315 if (openfile->mark_begin_x <= indent_len)
316 openfile->mark_begin_x = indent_new;
317 else
318 openfile->mark_begin_x -= indent_shift;
319 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000320
David Lawrence Ramseyac37b042006-05-03 12:59:05 +0000321 if (f == openfile->current && openfile->current_x >
David Lawrence Ramseyeb4f90e2006-05-05 14:22:42 +0000322 indent_new) {
323 if (openfile->current_x <= indent_len)
324 openfile->current_x = indent_new;
325 else
326 openfile->current_x -= indent_shift;
327 }
David Lawrence Ramsey7194a612006-04-29 16:11:21 +0000328
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000329 /* We've unindented, so set indent_changed to TRUE. */
330 if (!indent_changed)
331 indent_changed = TRUE;
332 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000333 }
334 }
335
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000336 if (!unindent)
David Lawrence Ramsey25456862006-05-05 15:43:52 +0000337 /* Clean up. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000338 free(line_indent);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000339
340 if (indent_changed) {
341 /* Mark the file as modified. */
342 set_modified();
343
344 /* Update the screen. */
345 edit_refresh();
346 }
347}
348
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000349/* Indent the current line, or all lines covered by the mark if the mark
350 * is on, tabsize columns. */
351void do_indent_void(void)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000352{
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000353 do_indent(tabsize);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000354}
355
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000356/* Unindent the current line, or all lines covered by the mark if the
357 * mark is on, tabsize columns. */
358void do_unindent(void)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000359{
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000360 do_indent(-tabsize);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000361}
362#endif /* !NANO_TINY */
363
David Lawrence Ramseyb0e04c02005-12-08 07:24:54 +0000364/* Someone hits Enter *gasp!* */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000365void do_enter(void)
366{
367 filestruct *newnode = make_new_node(openfile->current);
368 size_t extra = 0;
369
370 assert(openfile->current != NULL && openfile->current->data != NULL);
371
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000372#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000373 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
374 if (ISSET(AUTOINDENT)) {
375 /* If we are breaking the line in the indentation, the new
376 * indentation should have only current_x characters, and
377 * current_x should not change. */
378 extra = indent_length(openfile->current->data);
379 if (extra > openfile->current_x)
380 extra = openfile->current_x;
381 }
382#endif
383 newnode->data = charalloc(strlen(openfile->current->data +
384 openfile->current_x) + extra + 1);
385 strcpy(&newnode->data[extra], openfile->current->data +
386 openfile->current_x);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000387#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000388 if (ISSET(AUTOINDENT)) {
389 strncpy(newnode->data, openfile->current->data, extra);
390 openfile->totsize += mbstrlen(newnode->data);
391 }
392#endif
393 null_at(&openfile->current->data, openfile->current_x);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000394#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000395 if (openfile->mark_set && openfile->current ==
396 openfile->mark_begin && openfile->current_x <
397 openfile->mark_begin_x) {
398 openfile->mark_begin = newnode;
399 openfile->mark_begin_x += extra - openfile->current_x;
400 }
401#endif
402 openfile->current_x = extra;
403
404 if (openfile->current == openfile->filebot)
405 openfile->filebot = newnode;
406 splice_node(openfile->current, newnode,
407 openfile->current->next);
408
409 renumber(openfile->current);
410 openfile->current = newnode;
411
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000412 openfile->totsize++;
413 set_modified();
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +0000414
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000415 openfile->placewewant = xplustabs();
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +0000416
417 edit_refresh();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000418}
419
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000420#ifndef NANO_TINY
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000421/* Send a SIGKILL (unconditional kill) to the forked process in
422 * execute_command(). */
David Lawrence Ramsey8befda62005-12-06 19:39:56 +0000423RETSIGTYPE cancel_command(int signal)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000424{
425 if (kill(pid, SIGKILL) == -1)
426 nperror("kill");
427}
428
David Lawrence Ramsey0ed71712005-11-08 23:09:47 +0000429/* Execute command in a shell. Return TRUE on success. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000430bool execute_command(const char *command)
431{
432 int fd[2];
433 FILE *f;
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000434 char *shellenv;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000435 struct sigaction oldaction, newaction;
436 /* Original and temporary handlers for SIGINT. */
437 bool sig_failed = FALSE;
438 /* Did sigaction() fail without changing the signal handlers? */
439
440 /* Make our pipes. */
441 if (pipe(fd) == -1) {
442 statusbar(_("Could not pipe"));
443 return FALSE;
444 }
445
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000446 /* Check $SHELL for the shell to use. If it isn't set, use
David Lawrence Ramsey1932dfb2005-11-29 05:52:49 +0000447 * /bin/sh. Note that $SHELL should contain only a path, with no
448 * arguments. */
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000449 shellenv = getenv("SHELL");
450 if (shellenv == NULL)
451 shellenv = "/bin/sh";
452
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000453 /* Fork a child. */
454 if ((pid = fork()) == 0) {
455 close(fd[0]);
456 dup2(fd[1], fileno(stdout));
457 dup2(fd[1], fileno(stderr));
458
459 /* If execl() returns at all, there was an error. */
David Lawrence Ramsey5da68ee2005-11-29 05:21:06 +0000460 execl(shellenv, tail(shellenv), "-c", command, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000461 exit(0);
462 }
463
David Lawrence Ramseyc838a4c2006-04-26 18:33:50 +0000464 /* Continue as parent. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000465 close(fd[1]);
466
467 if (pid == -1) {
468 close(fd[0]);
469 statusbar(_("Could not fork"));
470 return FALSE;
471 }
472
473 /* Before we start reading the forked command's output, we set
474 * things up so that Ctrl-C will cancel the new process. */
475
476 /* Enable interpretation of the special control keys so that we get
477 * SIGINT when Ctrl-C is pressed. */
478 enable_signals();
479
480 if (sigaction(SIGINT, NULL, &newaction) == -1) {
481 sig_failed = TRUE;
482 nperror("sigaction");
483 } else {
484 newaction.sa_handler = cancel_command;
485 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
486 sig_failed = TRUE;
487 nperror("sigaction");
488 }
489 }
490
491 /* Note that now oldaction is the previous SIGINT signal handler,
492 * to be restored later. */
493
494 f = fdopen(fd[0], "rb");
495 if (f == NULL)
496 nperror("fdopen");
497
498 read_file(f, "stdin");
499
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000500 if (wait(NULL) == -1)
501 nperror("wait");
502
503 if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
504 nperror("sigaction");
505
David Lawrence Ramsey8b9c91b2007-12-18 01:28:53 +0000506 /* Restore the terminal to its previous state. In the process,
507 * disable interpretation of the special control keys so that we can
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000508 * use Ctrl-C for other things. */
David Lawrence Ramsey8b9c91b2007-12-18 01:28:53 +0000509 terminal_init();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000510
511 return TRUE;
512}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000513#endif /* !NANO_TINY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000514
515#ifndef DISABLE_WRAPPING
David Lawrence Ramseyef0d5a72006-05-22 02:08:49 +0000516/* Unset the prepend_wrap flag. We need to do this as soon as we do
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000517 * something other than type text. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000518void wrap_reset(void)
519{
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000520 prepend_wrap = FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000521}
522
523/* We wrap the given line. Precondition: we assume the cursor has been
David Lawrence Ramsey139fa652006-05-22 01:26:24 +0000524 * moved forward since the last typed character. Return TRUE if we
525 * wrapped, and FALSE otherwise. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000526bool do_wrap(filestruct *line)
527{
528 size_t line_len;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000529 /* The length of the line we wrap. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000530 ssize_t wrap_loc;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000531 /* The index of line->data where we wrap. */
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000532#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000533 const char *indent_string = NULL;
534 /* Indentation to prepend to the new line. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000535 size_t indent_len = 0;
536 /* The length of indent_string. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000537#endif
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000538 const char *after_break;
539 /* The text after the wrap point. */
540 size_t after_break_len;
541 /* The length of after_break. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000542 bool prepending = FALSE;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000543 /* Do we prepend to the next line? */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000544 const char *next_line = NULL;
545 /* The next line, minus indentation. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000546 size_t next_line_len = 0;
547 /* The length of next_line. */
548 char *new_line = NULL;
549 /* The line we create. */
550 size_t new_line_len = 0;
551 /* The eventual length of new_line. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000552
553 /* There are three steps. First, we decide where to wrap. Then, we
554 * create the new wrap line. Finally, we clean up. */
555
556 /* Step 1, finding where to wrap. We are going to add a new line
557 * after a blank character. In this step, we call break_line() to
558 * get the location of the last blank we can break the line at, and
David Lawrence Ramseyd4686b82006-06-11 19:14:14 +0000559 * set wrap_loc to the location of the character after it, so that
560 * the blank is preserved at the end of the line.
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000561 *
562 * If there is no legal wrap point, or we reach the last character
563 * of the line while trying to find one, we should return without
564 * wrapping. Note that if autoindent is turned on, we don't break
565 * at the end of it! */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000566 assert(line != NULL && line->data != NULL);
567
568 /* Save the length of the line. */
569 line_len = strlen(line->data);
570
571 /* Find the last blank where we can break the line. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000572 wrap_loc = break_line(line->data, fill
573#ifndef DISABLE_HELP
574 , FALSE
575#endif
576 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000577
578 /* If we couldn't break the line, or we've reached the end of it, we
579 * don't wrap. */
580 if (wrap_loc == -1 || line->data[wrap_loc] == '\0')
581 return FALSE;
582
583 /* Otherwise, move forward to the character just after the blank. */
584 wrap_loc += move_mbright(line->data + wrap_loc, 0);
585
586 /* If we've reached the end of the line, we don't wrap. */
587 if (line->data[wrap_loc] == '\0')
588 return FALSE;
589
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000590#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000591 /* If autoindent is turned on, and we're on the character just after
592 * the indentation, we don't wrap. */
593 if (ISSET(AUTOINDENT)) {
594 /* Get the indentation of this line. */
595 indent_string = line->data;
596 indent_len = indent_length(indent_string);
597
598 if (wrap_loc == indent_len)
599 return FALSE;
600 }
601#endif
602
603 /* Step 2, making the new wrap line. It will consist of indentation
604 * followed by the text after the wrap point, optionally followed by
605 * a space (if the text after the wrap point doesn't end in a blank)
David Lawrence Ramsey03979d72006-06-11 19:15:59 +0000606 * and the text of the next line, if they can fit without wrapping,
607 * the next line exists, and the prepend_wrap flag is set. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000608
609 /* after_break is the text that will be wrapped to the next line. */
610 after_break = line->data + wrap_loc;
611 after_break_len = line_len - wrap_loc;
612
613 assert(strlen(after_break) == after_break_len);
614
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000615 /* We prepend the wrapped text to the next line, if the prepend_wrap
616 * flag is set, there is a next line, and prepending would not make
617 * the line too long. */
618 if (prepend_wrap && line != openfile->filebot) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000619 const char *end = after_break + move_mbleft(after_break,
620 after_break_len);
621
622 /* If after_break doesn't end in a blank, make sure it ends in a
623 * space. */
624 if (!is_blank_mbchar(end)) {
625 line_len++;
626 line->data = charealloc(line->data, line_len + 1);
627 line->data[line_len - 1] = ' ';
628 line->data[line_len] = '\0';
629 after_break = line->data + wrap_loc;
630 after_break_len++;
631 openfile->totsize++;
632 }
633
634 next_line = line->next->data;
635 next_line_len = strlen(next_line);
636
637 if (after_break_len + next_line_len <= fill) {
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000638 prepending = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000639 new_line_len += next_line_len;
640 }
641 }
642
643 /* new_line_len is now the length of the text that will be wrapped
644 * to the next line, plus (if we're prepending to it) the length of
645 * the text of the next line. */
646 new_line_len += after_break_len;
647
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000648#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000649 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000650 if (prepending) {
651 /* If we're prepending, the indentation will come from the
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000652 * next line. */
653 indent_string = next_line;
654 indent_len = indent_length(indent_string);
655 next_line += indent_len;
656 } else {
657 /* Otherwise, it will come from this line, in which case
658 * we should increase new_line_len to make room for it. */
659 new_line_len += indent_len;
660 openfile->totsize += mbstrnlen(indent_string, indent_len);
661 }
662 }
663#endif
664
665 /* Now we allocate the new line and copy the text into it. */
666 new_line = charalloc(new_line_len + 1);
667 new_line[0] = '\0';
668
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000669#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000670 if (ISSET(AUTOINDENT)) {
671 /* Copy the indentation. */
672 strncpy(new_line, indent_string, indent_len);
673 new_line[indent_len] = '\0';
674 new_line_len += indent_len;
675 }
676#endif
677
678 /* Copy all the text after the wrap point of the current line. */
679 strcat(new_line, after_break);
680
681 /* Break the current line at the wrap point. */
682 null_at(&line->data, wrap_loc);
683
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000684 if (prepending) {
685 /* If we're prepending, copy the text from the next line, minus
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000686 * the indentation that we already copied above. */
687 strcat(new_line, next_line);
688
689 free(line->next->data);
690 line->next->data = new_line;
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000691
692 /* If the NO_NEWLINES flag isn't set, and text has been added to
693 * the magicline, make a new magicline. */
694 if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0')
695 new_magicline();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000696 } else {
697 /* Otherwise, make a new line and copy the text after where we
698 * broke this line to the beginning of the new line. */
699 splice_node(openfile->current, make_new_node(openfile->current),
700 openfile->current->next);
701
David Lawrence Ramsey219a8142005-11-22 22:08:01 +0000702 /* If the current line is the last line of the file, move the
703 * last line of the file down to the next line. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000704 if (openfile->filebot == openfile->current)
705 openfile->filebot = openfile->current->next;
706
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000707 openfile->current->next->data = new_line;
708
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000709 openfile->totsize++;
710 }
711
712 /* Step 3, clean up. Reposition the cursor and mark, and do some
713 * other sundry things. */
714
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000715 /* Set the prepend_wrap flag, so that later wraps of this line will
716 * be prepended to the next line. */
717 prepend_wrap = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000718
David Lawrence Ramsey2829aae2006-05-22 01:24:09 +0000719 /* Each line knows its number. We recalculate these if we inserted
720 * a new line. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000721 if (!prepending)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000722 renumber(line);
723
724 /* If the cursor was after the break point, we must move it. We
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000725 * also clear the prepend_wrap flag in this case. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000726 if (openfile->current_x > wrap_loc) {
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000727 prepend_wrap = FALSE;
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000728
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000729 openfile->current = openfile->current->next;
730 openfile->current_x -= wrap_loc
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000731#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000732 - indent_len
733#endif
734 ;
735 openfile->placewewant = xplustabs();
736 }
737
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000738#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000739 /* If the mark was on this line after the wrap point, we move it
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000740 * down. If it was on the next line and we prepended to that line,
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000741 * we move it right. */
742 if (openfile->mark_set) {
743 if (openfile->mark_begin == line && openfile->mark_begin_x >
744 wrap_loc) {
745 openfile->mark_begin = line->next;
746 openfile->mark_begin_x -= wrap_loc - indent_len + 1;
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000747 } else if (prepending && openfile->mark_begin == line->next)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000748 openfile->mark_begin_x += after_break_len;
749 }
750#endif
751
752 return TRUE;
753}
754#endif /* !DISABLE_WRAPPING */
755
David Lawrence Ramseyc7c04bb2005-11-29 21:30:00 +0000756#if !defined(DISABLE_HELP) || !defined(DISABLE_WRAPJUSTIFY)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000757/* We are trying to break a chunk off line. We find the last blank such
David Lawrence Ramseycd9a5f02005-09-20 06:12:54 +0000758 * that the display length to there is at most (goal + 1). If there is
759 * no such blank, then we find the first blank. We then take the last
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000760 * blank in that group of blanks. The terminating '\0' counts as a
761 * blank, as does a '\n' if newline is TRUE. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000762ssize_t break_line(const char *line, ssize_t goal
763#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +0000764 , bool newln
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000765#endif
766 )
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000767{
768 ssize_t blank_loc = -1;
769 /* Current tentative return value. Index of the last blank we
770 * found with short enough display width. */
771 ssize_t cur_loc = 0;
772 /* Current index in line. */
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +0000773 size_t cur_pos = 0;
774 /* Current column position in line. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000775 int line_len;
776
777 assert(line != NULL);
778
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +0000779 while (*line != '\0' && goal >= cur_pos) {
780 line_len = parse_mbchar(line, NULL, &cur_pos);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000781
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000782 if (is_blank_mbchar(line)
783#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +0000784 || (newln && *line == '\n')
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000785#endif
786 ) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000787 blank_loc = cur_loc;
788
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000789#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +0000790 if (newln && *line == '\n')
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000791 break;
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000792#endif
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000793 }
794
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000795 line += line_len;
796 cur_loc += line_len;
797 }
798
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +0000799 if (goal >= cur_pos)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000800 /* In fact, the whole line displays shorter than goal. */
801 return cur_loc;
802
803 if (blank_loc == -1) {
804 /* No blank was found that was short enough. */
805 bool found_blank = FALSE;
David Lawrence Ramsey5ab12ca2005-09-20 17:52:52 +0000806 ssize_t found_blank_loc = 0;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000807
808 while (*line != '\0') {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000809 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000810
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000811 if (is_blank_mbchar(line)
812#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +0000813 || (newln && *line == '\n')
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000814#endif
815 ) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000816 if (!found_blank)
817 found_blank = TRUE;
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +0000818 found_blank_loc = cur_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000819 } else if (found_blank)
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +0000820 return found_blank_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000821
822 line += line_len;
823 cur_loc += line_len;
824 }
825
826 return -1;
827 }
828
829 /* Move to the last blank after blank_loc, if there is one. */
830 line -= cur_loc;
831 line += blank_loc;
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000832 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000833 line += line_len;
834
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000835 while (*line != '\0' && (is_blank_mbchar(line)
836#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +0000837 || (newln && *line == '\n')
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000838#endif
839 )) {
David Lawrence Ramseycd243f52006-05-19 23:27:16 +0000840#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +0000841 if (newln && *line == '\n')
David Lawrence Ramseycd243f52006-05-19 23:27:16 +0000842 break;
843#endif
844
David Lawrence Ramsey39bd1b32006-05-20 13:11:56 +0000845 line_len = parse_mbchar(line, NULL, NULL);
846
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000847 line += line_len;
848 blank_loc += line_len;
849 }
850
851 return blank_loc;
852}
David Lawrence Ramseyc7c04bb2005-11-29 21:30:00 +0000853#endif /* !DISABLE_HELP || !DISABLE_WRAPJUSTIFY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000854
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000855#if !defined(NANO_TINY) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000856/* The "indentation" of a line is the whitespace between the quote part
857 * and the non-whitespace of the line. */
858size_t indent_length(const char *line)
859{
860 size_t len = 0;
861 char *blank_mb;
862 int blank_mb_len;
863
864 assert(line != NULL);
865
866 blank_mb = charalloc(mb_cur_max());
867
868 while (*line != '\0') {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000869 blank_mb_len = parse_mbchar(line, blank_mb, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000870
871 if (!is_blank_mbchar(blank_mb))
872 break;
873
874 line += blank_mb_len;
875 len += blank_mb_len;
876 }
877
878 free(blank_mb);
879
880 return len;
881}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000882#endif /* !NANO_TINY || !DISABLE_JUSTIFY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000883
884#ifndef DISABLE_JUSTIFY
885/* justify_format() replaces blanks with spaces and multiple spaces by 1
886 * (except it maintains up to 2 after a character in punct optionally
887 * followed by a character in brackets, and removes all from the end).
888 *
889 * justify_format() might make paragraph->data shorter, and change the
890 * actual pointer with null_at().
891 *
892 * justify_format() will not look at the first skip characters of
893 * paragraph. skip should be at most strlen(paragraph->data). The
894 * character at paragraph[skip + 1] must not be blank. */
895void justify_format(filestruct *paragraph, size_t skip)
896{
897 char *end, *new_end, *new_paragraph_data;
898 size_t shift = 0;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000899#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000900 size_t mark_shift = 0;
901#endif
902
903 /* These four asserts are assumptions about the input data. */
904 assert(paragraph != NULL);
905 assert(paragraph->data != NULL);
906 assert(skip < strlen(paragraph->data));
907 assert(!is_blank_mbchar(paragraph->data + skip));
908
909 end = paragraph->data + skip;
910 new_paragraph_data = charalloc(strlen(paragraph->data) + 1);
911 strncpy(new_paragraph_data, paragraph->data, skip);
912 new_end = new_paragraph_data + skip;
913
914 while (*end != '\0') {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000915 int end_len;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000916
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000917 /* If this character is blank, change it to a space if
918 * necessary, and skip over all blanks after it. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000919 if (is_blank_mbchar(end)) {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000920 end_len = parse_mbchar(end, NULL, NULL);
921
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000922 *new_end = ' ';
923 new_end++;
924 end += end_len;
925
926 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000927 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000928
929 end += end_len;
930 shift += end_len;
931
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000932#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000933 /* Keep track of the change in the current line. */
934 if (openfile->mark_set && openfile->mark_begin ==
935 paragraph && openfile->mark_begin_x >= end -
936 paragraph->data)
937 mark_shift += end_len;
938#endif
939 }
940 /* If this character is punctuation optionally followed by a
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000941 * bracket and then followed by blanks, change no more than two
942 * of the blanks to spaces if necessary, and skip over all
943 * blanks after them. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000944 } else if (mbstrchr(punct, end) != NULL) {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000945 end_len = parse_mbchar(end, NULL, NULL);
946
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000947 while (end_len > 0) {
948 *new_end = *end;
949 new_end++;
950 end++;
951 end_len--;
952 }
953
954 if (*end != '\0' && mbstrchr(brackets, end) != NULL) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000955 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000956
957 while (end_len > 0) {
958 *new_end = *end;
959 new_end++;
960 end++;
961 end_len--;
962 }
963 }
964
965 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000966 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000967
968 *new_end = ' ';
969 new_end++;
970 end += end_len;
971 }
972
973 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000974 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000975
976 *new_end = ' ';
977 new_end++;
978 end += end_len;
979 }
980
981 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000982 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000983
984 end += end_len;
985 shift += end_len;
986
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000987#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000988 /* Keep track of the change in the current line. */
989 if (openfile->mark_set && openfile->mark_begin ==
990 paragraph && openfile->mark_begin_x >= end -
991 paragraph->data)
992 mark_shift += end_len;
993#endif
994 }
995 /* If this character is neither blank nor punctuation, leave it
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000996 * unchanged. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000997 } else {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000998 end_len = parse_mbchar(end, NULL, NULL);
999
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001000 while (end_len > 0) {
1001 *new_end = *end;
1002 new_end++;
1003 end++;
1004 end_len--;
1005 }
1006 }
1007 }
1008
1009 assert(*end == '\0');
1010
1011 *new_end = *end;
1012
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001013 /* If there are spaces at the end of the line, remove them. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001014 while (new_end > new_paragraph_data + skip &&
1015 *(new_end - 1) == ' ') {
1016 new_end--;
1017 shift++;
1018 }
1019
1020 if (shift > 0) {
1021 openfile->totsize -= shift;
1022 null_at(&new_paragraph_data, new_end - new_paragraph_data);
1023 free(paragraph->data);
1024 paragraph->data = new_paragraph_data;
1025
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001026#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001027 /* Adjust the mark coordinates to compensate for the change in
1028 * the current line. */
1029 if (openfile->mark_set && openfile->mark_begin == paragraph) {
1030 openfile->mark_begin_x -= mark_shift;
1031 if (openfile->mark_begin_x > new_end - new_paragraph_data)
1032 openfile->mark_begin_x = new_end - new_paragraph_data;
1033 }
1034#endif
1035 } else
1036 free(new_paragraph_data);
1037}
1038
1039/* The "quote part" of a line is the largest initial substring matching
1040 * the quote string. This function returns the length of the quote part
1041 * of the given line.
1042 *
1043 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1044 * quotestr. */
1045size_t quote_length(const char *line)
1046{
1047#ifdef HAVE_REGEX_H
1048 regmatch_t matches;
1049 int rc = regexec(&quotereg, line, 1, &matches, 0);
1050
1051 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
1052 return 0;
1053 /* matches.rm_so should be 0, since the quote string should start
1054 * with the caret ^. */
1055 return matches.rm_eo;
1056#else /* !HAVE_REGEX_H */
1057 size_t qdepth = 0;
1058
1059 /* Compute quote depth level. */
1060 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
1061 qdepth += quotelen;
1062 return qdepth;
1063#endif /* !HAVE_REGEX_H */
1064}
1065
1066/* a_line and b_line are lines of text. The quotation part of a_line is
1067 * the first a_quote characters. Check that the quotation part of
1068 * b_line is the same. */
1069bool quotes_match(const char *a_line, size_t a_quote, const char
1070 *b_line)
1071{
1072 /* Here is the assumption about a_quote. */
1073 assert(a_quote == quote_length(a_line));
1074
1075 return (a_quote == quote_length(b_line) &&
1076 strncmp(a_line, b_line, a_quote) == 0);
1077}
1078
1079/* We assume a_line and b_line have no quote part. Then, we return
1080 * whether b_line could follow a_line in a paragraph. */
1081bool indents_match(const char *a_line, size_t a_indent, const char
1082 *b_line, size_t b_indent)
1083{
1084 assert(a_indent == indent_length(a_line));
1085 assert(b_indent == indent_length(b_line));
1086
1087 return (b_indent <= a_indent &&
1088 strncmp(a_line, b_line, b_indent) == 0);
1089}
1090
1091/* Is foo the beginning of a paragraph?
1092 *
1093 * A line of text consists of a "quote part", followed by an
1094 * "indentation part", followed by text. The functions quote_length()
1095 * and indent_length() calculate these parts.
1096 *
1097 * A line is "part of a paragraph" if it has a part not in the quote
1098 * part or the indentation.
1099 *
1100 * A line is "the beginning of a paragraph" if it is part of a
1101 * paragraph and
1102 * 1) it is the top line of the file, or
1103 * 2) the line above it is not part of a paragraph, or
1104 * 3) the line above it does not have precisely the same quote
1105 * part, or
1106 * 4) the indentation of this line is not an initial substring of
1107 * the indentation of the previous line, or
1108 * 5) this line has no quote part and some indentation, and
1109 * autoindent isn't turned on.
1110 * The reason for number 5) is that if autoindent isn't turned on,
1111 * then an indented line is expected to start a paragraph, as in
1112 * books. Thus, nano can justify an indented paragraph only if
1113 * autoindent is turned on. */
1114bool begpar(const filestruct *const foo)
1115{
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +00001116 size_t quote_len, indent_len, temp_id_len;
1117
1118 if (foo == NULL)
1119 return FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001120
1121 /* Case 1). */
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +00001122 if (foo == openfile->fileage)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001123 return TRUE;
1124
1125 quote_len = quote_length(foo->data);
1126 indent_len = indent_length(foo->data + quote_len);
1127
1128 /* Not part of a paragraph. */
1129 if (foo->data[quote_len + indent_len] == '\0')
1130 return FALSE;
1131
1132 /* Case 3). */
1133 if (!quotes_match(foo->data, quote_len, foo->prev->data))
1134 return TRUE;
1135
1136 temp_id_len = indent_length(foo->prev->data + quote_len);
1137
1138 /* Case 2) or 5) or 4). */
1139 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
1140 (quote_len == 0 && indent_len > 0
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001141#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001142 && !ISSET(AUTOINDENT)
1143#endif
1144 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
1145 foo->data + quote_len, indent_len))
1146 return TRUE;
1147
1148 return FALSE;
1149}
1150
1151/* Is foo inside a paragraph? */
1152bool inpar(const filestruct *const foo)
1153{
1154 size_t quote_len;
1155
1156 if (foo == NULL)
1157 return FALSE;
1158
1159 quote_len = quote_length(foo->data);
1160
David Lawrence Ramsey21014032005-11-09 20:33:42 +00001161 return (foo->data[quote_len + indent_length(foo->data +
1162 quote_len)] != '\0');
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001163}
1164
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001165/* Move the next par_len lines, starting with first_line, into the
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001166 * justify buffer, leaving copies of those lines in place. Assume that
1167 * par_len is greater than zero, and that there are enough lines after
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001168 * first_line. */
1169void backup_lines(filestruct *first_line, size_t par_len)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001170{
1171 filestruct *top = first_line;
1172 /* The top of the paragraph we're backing up. */
1173 filestruct *bot = first_line;
1174 /* The bottom of the paragraph we're backing up. */
1175 size_t i;
1176 /* Generic loop variable. */
1177 size_t current_x_save = openfile->current_x;
1178 ssize_t fl_lineno_save = first_line->lineno;
1179 ssize_t edittop_lineno_save = openfile->edittop->lineno;
1180 ssize_t current_lineno_save = openfile->current->lineno;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001181#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001182 bool old_mark_set = openfile->mark_set;
1183 ssize_t mb_lineno_save = 0;
1184 size_t mark_begin_x_save = 0;
1185
1186 if (old_mark_set) {
1187 mb_lineno_save = openfile->mark_begin->lineno;
1188 mark_begin_x_save = openfile->mark_begin_x;
1189 }
1190#endif
1191
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001192 /* par_len will be one greater than the number of lines between
1193 * current and filebot if filebot is the last line in the
1194 * paragraph. */
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001195 assert(par_len > 0 && openfile->current->lineno + par_len <=
David Lawrence Ramsey24777c02005-12-01 05:49:08 +00001196 openfile->filebot->lineno + 1);
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001197
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001198 /* Move bot down par_len lines to the line after the last line of
1199 * the paragraph, if there is one. */
1200 for (i = par_len; i > 0 && bot != openfile->filebot; i--)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001201 bot = bot->next;
1202
1203 /* Move the paragraph from the current buffer's filestruct to the
1204 * justify buffer. */
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001205 move_to_filestruct(&jusbuffer, &jusbottom, top, 0, bot,
David Lawrence Ramseyf0575cf2005-11-09 23:27:51 +00001206 (i == 1 && bot == openfile->filebot) ? strlen(bot->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001207
1208 /* Copy the paragraph back to the current buffer's filestruct from
1209 * the justify buffer. */
1210 copy_from_filestruct(jusbuffer, jusbottom);
1211
1212 /* Move upward from the last line of the paragraph to the first
1213 * line, putting first_line, edittop, current, and mark_begin at the
1214 * same lines in the copied paragraph that they had in the original
1215 * paragraph. */
David Lawrence Ramseyee43ea62007-04-22 15:04:05 +00001216 if (openfile->current != openfile->fileage) {
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001217 top = openfile->current->prev;
David Lawrence Ramseyee43ea62007-04-22 15:04:05 +00001218#ifndef NANO_TINY
1219 if (old_mark_set &&
1220 openfile->current->lineno == mb_lineno_save) {
1221 openfile->mark_begin = openfile->current;
1222 openfile->mark_begin_x = mark_begin_x_save;
1223 }
1224#endif
1225 } else
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001226 top = openfile->current;
David Lawrence Ramseye8d505b2005-11-10 03:40:45 +00001227 for (i = par_len; i > 0 && top != NULL; i--) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001228 if (top->lineno == fl_lineno_save)
1229 first_line = top;
1230 if (top->lineno == edittop_lineno_save)
1231 openfile->edittop = top;
1232 if (top->lineno == current_lineno_save)
1233 openfile->current = top;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001234#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001235 if (old_mark_set && top->lineno == mb_lineno_save) {
1236 openfile->mark_begin = top;
1237 openfile->mark_begin_x = mark_begin_x_save;
1238 }
1239#endif
1240 top = top->prev;
1241 }
1242
1243 /* Put current_x at the same place in the copied paragraph that it
1244 * had in the original paragraph. */
1245 openfile->current_x = current_x_save;
1246
1247 set_modified();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001248}
1249
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001250/* Find the beginning of the current paragraph if we're in one, or the
1251 * beginning of the next paragraph if we're not. Afterwards, save the
1252 * quote length and paragraph length in *quote and *par. Return TRUE if
David Lawrence Ramsey139fa652006-05-22 01:26:24 +00001253 * we found a paragraph, and FALSE if there was an error or we didn't
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001254 * find a paragraph.
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001255 *
1256 * See the comment at begpar() for more about when a line is the
1257 * beginning of a paragraph. */
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001258bool find_paragraph(size_t *const quote, size_t *const par)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001259{
1260 size_t quote_len;
1261 /* Length of the initial quotation of the paragraph we search
1262 * for. */
1263 size_t par_len;
1264 /* Number of lines in the paragraph we search for. */
1265 filestruct *current_save;
1266 /* The line at the beginning of the paragraph we search for. */
1267 ssize_t current_y_save;
1268 /* The y-coordinate at the beginning of the paragraph we search
1269 * for. */
1270
1271#ifdef HAVE_REGEX_H
1272 if (quoterc != 0) {
1273 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
1274 return FALSE;
1275 }
1276#endif
1277
1278 assert(openfile->current != NULL);
1279
David Lawrence Ramsey1be131a2005-11-11 03:55:52 +00001280 /* If we're at the end of the last line of the file, it means that
1281 * there aren't any paragraphs left, so get out. */
1282 if (openfile->current == openfile->filebot && openfile->current_x ==
1283 strlen(openfile->filebot->data))
1284 return FALSE;
1285
1286 /* If the current line isn't in a paragraph, move forward to the
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001287 * last line of the next paragraph, if any. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001288 if (!inpar(openfile->current)) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001289 do_para_end(FALSE);
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001290
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001291 /* If we end up past the beginning of the line, it means that
1292 * we're at the end of the last line of the file, and the line
1293 * isn't blank, in which case the last line of the file is the
1294 * last line of the next paragraph.
1295 *
1296 * Otherwise, if we end up on a line that's in a paragraph, it
1297 * means that we're on the line after the last line of the next
1298 * paragraph, in which case we should move back to the last line
1299 * of the next paragraph. */
1300 if (openfile->current_x == 0) {
1301 if (!inpar(openfile->current->prev))
1302 return FALSE;
1303 if (openfile->current != openfile->fileage)
1304 openfile->current = openfile->current->prev;
1305 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001306 }
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001307
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001308 /* If the current line isn't the first line of the paragraph, move
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001309 * back to the first line of the paragraph. */
1310 if (!begpar(openfile->current))
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001311 do_para_begin(FALSE);
1312
1313 /* Now current is the first line of the paragraph. Set quote_len to
1314 * the quotation length of that line, and set par_len to the number
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001315 * of lines in this paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001316 quote_len = quote_length(openfile->current->data);
1317 current_save = openfile->current;
1318 current_y_save = openfile->current_y;
1319 do_para_end(FALSE);
1320 par_len = openfile->current->lineno - current_save->lineno;
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001321
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001322 /* If we end up past the beginning of the line, it means that we're
1323 * at the end of the last line of the file, and the line isn't
1324 * blank, in which case the last line of the file is part of the
1325 * paragraph. */
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00001326 if (openfile->current_x > 0)
1327 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001328 openfile->current = current_save;
1329 openfile->current_y = current_y_save;
1330
1331 /* Save the values of quote_len and par_len. */
1332 assert(quote != NULL && par != NULL);
1333
1334 *quote = quote_len;
1335 *par = par_len;
1336
1337 return TRUE;
1338}
1339
1340/* If full_justify is TRUE, justify the entire file. Otherwise, justify
1341 * the current paragraph. */
1342void do_justify(bool full_justify)
1343{
1344 filestruct *first_par_line = NULL;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001345 /* Will be the first line of the justified paragraph(s), if any.
1346 * For restoring after unjustify. */
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001347 filestruct *last_par_line = NULL;
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001348 /* Will be the line after the last line of the justified
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001349 * paragraph(s), if any. Also for restoring after unjustify. */
David Lawrence Ramsey82b5deb2005-11-10 06:07:57 +00001350 bool filebot_inpar = FALSE;
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001351 /* Whether the text at filebot is part of the current
1352 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001353
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00001354 /* We save these variables to be restored if the user
1355 * unjustifies. */
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00001356 filestruct *edittop_save = openfile->edittop;
1357 filestruct *current_save = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001358 size_t current_x_save = openfile->current_x;
1359 size_t pww_save = openfile->placewewant;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001360 size_t totsize_save = openfile->totsize;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001361#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001362 filestruct *mark_begin_save = openfile->mark_begin;
1363 size_t mark_begin_x_save = openfile->mark_begin_x;
1364#endif
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00001365 bool modified_save = openfile->modified;
1366
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001367 int kbinput;
1368 bool meta_key, func_key, s_or_t, ran_func, finished;
Chris Allegretta0018d8e2008-03-13 08:23:52 +00001369 const sc *s;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001370
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001371 /* Move to the beginning of the current line, so that justifying at
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00001372 * the end of the last line of the file, if that line isn't blank,
1373 * will work the first time through. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001374 openfile->current_x = 0;
1375
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001376 /* If we're justifying the entire file, start at the beginning. */
1377 if (full_justify)
1378 openfile->current = openfile->fileage;
1379
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001380 while (TRUE) {
1381 size_t i;
1382 /* Generic loop variable. */
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001383 filestruct *curr_first_par_line;
1384 /* The first line of the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001385 size_t quote_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001386 /* Length of the initial quotation of the current
1387 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001388 size_t indent_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001389 /* Length of the initial indentation of the current
1390 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001391 size_t par_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001392 /* Number of lines in the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001393 ssize_t break_pos;
1394 /* Where we will break lines. */
1395 char *indent_string;
1396 /* The first indentation that doesn't match the initial
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001397 * indentation of the current paragraph. This is put at the
1398 * beginning of every line broken off the first justified
1399 * line of the paragraph. Note that this works because a
1400 * paragraph can only contain two indentations at most: the
1401 * initial one, and a different one starting on a line after
1402 * the first. See the comment at begpar() for more about
1403 * when a line is part of a paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001404
1405 /* Find the first line of the paragraph to be justified. That
1406 * is the start of this paragraph if we're in one, or the start
1407 * of the next otherwise. Save the quote length and paragraph
1408 * length (number of lines). Don't refresh the screen yet,
1409 * since we'll do that after we justify.
1410 *
1411 * If the search failed, we do one of two things. If we're
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00001412 * justifying the whole file, and we've found at least one
1413 * paragraph, it means that we should justify all the way to the
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001414 * last line of the file, so set the last line of the text to be
1415 * justified to the last line of the file and break out of the
1416 * loop. Otherwise, it means that there are no paragraph(s) to
1417 * justify, so refresh the screen and get out. */
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001418 if (!find_paragraph(&quote_len, &par_len)) {
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00001419 if (full_justify && first_par_line != NULL) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001420 last_par_line = openfile->filebot;
1421 break;
1422 } else {
1423 edit_refresh();
1424 return;
1425 }
1426 }
1427
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001428 /* par_len will be one greater than the number of lines between
1429 * current and filebot if filebot is the last line in the
1430 * paragraph. Set filebot_inpar to TRUE if this is the case. */
1431 filebot_inpar = (openfile->current->lineno + par_len ==
1432 openfile->filebot->lineno + 1);
1433
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001434 /* If we haven't already done it, move the original paragraph(s)
1435 * to the justify buffer, splice a copy of the original
1436 * paragraph(s) into the file in the same place, and set
1437 * first_par_line to the first line of the copy. */
1438 if (first_par_line == NULL) {
1439 backup_lines(openfile->current, full_justify ?
David Lawrence Ramsey53f641f2005-11-10 21:57:56 +00001440 openfile->filebot->lineno - openfile->current->lineno +
1441 ((openfile->filebot->data[0] != '\0') ? 1 : 0) :
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001442 par_len);
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001443 first_par_line = openfile->current;
1444 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001445
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001446 /* Set curr_first_par_line to the first line of the current
1447 * paragraph. */
1448 curr_first_par_line = openfile->current;
1449
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001450 /* Initialize indent_string to a blank string. */
1451 indent_string = mallocstrcpy(NULL, "");
1452
1453 /* Find the first indentation in the paragraph that doesn't
David Lawrence Ramsey8602fd62006-05-28 18:43:21 +00001454 * match the indentation of the first line, and save it in
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001455 * indent_string. If all the indentations are the same, save
1456 * the indentation of the first line in indent_string. */
1457 {
1458 const filestruct *indent_line = openfile->current;
1459 bool past_first_line = FALSE;
1460
1461 for (i = 0; i < par_len; i++) {
1462 indent_len = quote_len +
1463 indent_length(indent_line->data + quote_len);
1464
1465 if (indent_len != strlen(indent_string)) {
1466 indent_string = mallocstrncpy(indent_string,
1467 indent_line->data, indent_len + 1);
1468 indent_string[indent_len] = '\0';
1469
1470 if (past_first_line)
1471 break;
1472 }
1473
1474 if (indent_line == openfile->current)
1475 past_first_line = TRUE;
1476
1477 indent_line = indent_line->next;
1478 }
1479 }
1480
1481 /* Now tack all the lines of the paragraph together, skipping
1482 * the quoting and indentation on all lines after the first. */
1483 for (i = 0; i < par_len - 1; i++) {
1484 filestruct *next_line = openfile->current->next;
1485 size_t line_len = strlen(openfile->current->data);
1486 size_t next_line_len =
1487 strlen(openfile->current->next->data);
1488
1489 indent_len = quote_len +
1490 indent_length(openfile->current->next->data +
1491 quote_len);
1492
1493 next_line_len -= indent_len;
1494 openfile->totsize -= indent_len;
1495
1496 /* We're just about to tack the next line onto this one. If
1497 * this line isn't empty, make sure it ends in a space. */
1498 if (line_len > 0 &&
1499 openfile->current->data[line_len - 1] != ' ') {
1500 line_len++;
1501 openfile->current->data =
1502 charealloc(openfile->current->data,
1503 line_len + 1);
1504 openfile->current->data[line_len - 1] = ' ';
1505 openfile->current->data[line_len] = '\0';
1506 openfile->totsize++;
1507 }
1508
1509 openfile->current->data =
1510 charealloc(openfile->current->data, line_len +
1511 next_line_len + 1);
1512 strcat(openfile->current->data, next_line->data +
1513 indent_len);
1514
David Lawrence Ramsey9bedc4b2005-11-09 19:51:48 +00001515 /* Don't destroy edittop or filebot! */
David Lawrence Ramsey32bd29e2005-11-09 03:44:23 +00001516 if (next_line == openfile->edittop)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001517 openfile->edittop = openfile->current;
David Lawrence Ramsey9bedc4b2005-11-09 19:51:48 +00001518 if (next_line == openfile->filebot)
1519 openfile->filebot = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001520
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001521#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001522 /* Adjust the mark coordinates to compensate for the change
1523 * in the next line. */
1524 if (openfile->mark_set && openfile->mark_begin ==
1525 next_line) {
1526 openfile->mark_begin = openfile->current;
1527 openfile->mark_begin_x += line_len - indent_len;
1528 }
1529#endif
1530
1531 unlink_node(next_line);
1532 delete_node(next_line);
1533
1534 /* If we've removed the next line, we need to go through
1535 * this line again. */
1536 i--;
1537
1538 par_len--;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001539 openfile->totsize--;
1540 }
1541
1542 /* Call justify_format() on the paragraph, which will remove
1543 * excess spaces from it and change all blank characters to
1544 * spaces. */
1545 justify_format(openfile->current, quote_len +
1546 indent_length(openfile->current->data + quote_len));
1547
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001548 while (par_len > 0 && strlenpt(openfile->current->data) >
1549 fill) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001550 size_t line_len = strlen(openfile->current->data);
1551
1552 indent_len = strlen(indent_string);
1553
1554 /* If this line is too long, try to wrap it to the next line
1555 * to make it short enough. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001556 break_pos = break_line(openfile->current->data + indent_len,
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001557 fill - strnlenpt(openfile->current->data, indent_len)
1558#ifndef DISABLE_HELP
1559 , FALSE
1560#endif
1561 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001562
1563 /* We can't break the line, or don't need to, so get out. */
1564 if (break_pos == -1 || break_pos + indent_len == line_len)
1565 break;
1566
1567 /* Move forward to the character after the indentation and
1568 * just after the space. */
1569 break_pos += indent_len + 1;
1570
1571 assert(break_pos <= line_len);
1572
1573 /* Make a new line, and copy the text after where we're
1574 * going to break this line to the beginning of the new
1575 * line. */
1576 splice_node(openfile->current,
1577 make_new_node(openfile->current),
1578 openfile->current->next);
1579
1580 /* If this paragraph is non-quoted, and autoindent isn't
1581 * turned on, set the indentation length to zero so that the
1582 * indentation is treated as part of the line. */
1583 if (quote_len == 0
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001584#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001585 && !ISSET(AUTOINDENT)
1586#endif
1587 )
1588 indent_len = 0;
1589
1590 /* Copy the text after where we're going to break the
1591 * current line to the next line. */
1592 openfile->current->next->data = charalloc(indent_len + 1 +
1593 line_len - break_pos);
1594 strncpy(openfile->current->next->data, indent_string,
1595 indent_len);
1596 strcpy(openfile->current->next->data + indent_len,
1597 openfile->current->data + break_pos);
1598
1599 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001600 openfile->totsize += indent_len + 1;
1601
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001602#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001603 /* Adjust the mark coordinates to compensate for the change
1604 * in the current line. */
1605 if (openfile->mark_set && openfile->mark_begin ==
1606 openfile->current && openfile->mark_begin_x >
1607 break_pos) {
1608 openfile->mark_begin = openfile->current->next;
1609 openfile->mark_begin_x -= break_pos - indent_len;
1610 }
1611#endif
1612
1613 /* Break the current line. */
1614 null_at(&openfile->current->data, break_pos);
1615
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001616 /* If the current line is the last line of the file, move
David Lawrence Ramseyb885c9c2005-11-10 05:20:25 +00001617 * the last line of the file down to the next line. */
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001618 if (openfile->filebot == openfile->current)
1619 openfile->filebot = openfile->filebot->next;
1620
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001621 /* Go to the next line. */
1622 par_len--;
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001623 openfile->current_y++;
1624 openfile->current = openfile->current->next;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001625 }
1626
1627 /* We're done breaking lines, so we don't need indent_string
1628 * anymore. */
1629 free(indent_string);
1630
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001631 /* Go to the next line, if possible. If there is no next line,
1632 * move to the end of the current line. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001633 if (openfile->current != openfile->filebot) {
1634 openfile->current_y++;
1635 openfile->current = openfile->current->next;
1636 } else
1637 openfile->current_x = strlen(openfile->current->data);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001638
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001639 /* Renumber the lines of the now-justified current paragraph,
1640 * since both find_paragraph() and edit_refresh() need the line
1641 * numbers to be right. */
1642 renumber(curr_first_par_line);
David Lawrence Ramseyad1b64c2005-11-29 19:00:09 +00001643
1644 /* We've just finished justifying the paragraph. If we're not
1645 * justifying the entire file, break out of the loop.
1646 * Otherwise, continue the loop so that we justify all the
1647 * paragraphs in the file. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001648 if (!full_justify)
1649 break;
1650 }
1651
1652 /* We are now done justifying the paragraph or the file, so clean
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001653 * up. current_y and totsize have been maintained above. If we
David Lawrence Ramseyad1b64c2005-11-29 19:00:09 +00001654 * actually justified something, set last_par_line to the new end of
1655 * the paragraph. */
1656 if (first_par_line != NULL)
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001657 last_par_line = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001658
1659 edit_refresh();
1660
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00001661#ifndef NANO_TINY
David Lawrence Ramsey1c5af642006-05-10 15:15:06 +00001662 /* We're going to set jump_buf so that we return here after a
1663 * SIGWINCH instead of to main(). Indicate this. */
1664 jump_buf_main = FALSE;
1665
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00001666 /* Return here after a SIGWINCH. */
David Lawrence Ramsey1c5af642006-05-10 15:15:06 +00001667 sigsetjmp(jump_buf, 1);
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00001668#endif
1669
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001670 statusbar(_("Can now UnJustify!"));
1671
1672 /* If constant cursor position display is on, make sure the current
1673 * cursor position will be properly displayed on the statusbar. */
1674 if (ISSET(CONST_UPDATE))
1675 do_cursorpos(TRUE);
1676
1677 /* Display the shortcut list with UnJustify. */
1678 shortcut_init(TRUE);
1679 display_main_list();
1680
1681 /* Now get a keystroke and see if it's unjustify. If not, put back
1682 * the keystroke and return. */
1683 kbinput = do_input(&meta_key, &func_key, &s_or_t, &ran_func,
1684 &finished, FALSE);
Chris Allegretta0018d8e2008-03-13 08:23:52 +00001685 s = get_shortcut(currmenu, &kbinput, &meta_key, &func_key);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001686
Chris Allegretta0018d8e2008-03-13 08:23:52 +00001687 if (s && s->scfunc == do_uncut_text) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001688 /* Splice the justify buffer back into the file, but only if we
1689 * actually justified something. */
1690 if (first_par_line != NULL) {
1691 filestruct *top_save;
1692
1693 /* Partition the filestruct so that it contains only the
1694 * text of the justified paragraph. */
1695 filepart = partition_filestruct(first_par_line, 0,
David Lawrence Ramseyccd1b7b2005-11-18 20:21:48 +00001696 last_par_line, filebot_inpar ?
1697 strlen(last_par_line->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001698
1699 /* Remove the text of the justified paragraph, and
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001700 * replace it with the text in the justify buffer. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001701 free_filestruct(openfile->fileage);
1702 openfile->fileage = jusbuffer;
1703 openfile->filebot = jusbottom;
1704
1705 top_save = openfile->fileage;
1706
1707 /* Unpartition the filestruct so that it contains all the
1708 * text again. Note that the justified paragraph has been
1709 * replaced with the unjustified paragraph. */
1710 unpartition_filestruct(&filepart);
1711
1712 /* Renumber starting with the beginning line of the old
1713 * partition. */
1714 renumber(top_save);
1715
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001716 /* Restore the justify we just did (ungrateful user!). */
1717 openfile->edittop = edittop_save;
1718 openfile->current = current_save;
1719 openfile->current_x = current_x_save;
1720 openfile->placewewant = pww_save;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001721 openfile->totsize = totsize_save;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001722#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001723 if (openfile->mark_set) {
1724 openfile->mark_begin = mark_begin_save;
1725 openfile->mark_begin_x = mark_begin_x_save;
1726 }
1727#endif
1728 openfile->modified = modified_save;
1729
1730 /* Clear the justify buffer. */
1731 jusbuffer = NULL;
1732
1733 if (!openfile->modified)
1734 titlebar(NULL);
1735 edit_refresh();
1736 }
1737 } else {
1738 unget_kbinput(kbinput, meta_key, func_key);
1739
1740 /* Blow away the text in the justify buffer. */
1741 free_filestruct(jusbuffer);
1742 jusbuffer = NULL;
1743 }
1744
1745 blank_statusbar();
1746
1747 /* Display the shortcut list with UnCut. */
1748 shortcut_init(FALSE);
1749 display_main_list();
1750}
1751
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001752/* Justify the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001753void do_justify_void(void)
1754{
1755 do_justify(FALSE);
1756}
1757
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001758/* Justify the entire file. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001759void do_full_justify(void)
1760{
1761 do_justify(TRUE);
1762}
1763#endif /* !DISABLE_JUSTIFY */
1764
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001765#ifndef DISABLE_SPELLER
1766/* A word is misspelled in the file. Let the user replace it. We
1767 * return FALSE if the user cancels. */
1768bool do_int_spell_fix(const char *word)
1769{
1770 char *save_search, *save_replace;
1771 size_t match_len, current_x_save = openfile->current_x;
1772 size_t pww_save = openfile->placewewant;
Chris Allegretta10f868d2008-03-14 04:08:51 +00001773 bool meta_key = FALSE, func_key = FALSE;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001774 filestruct *edittop_save = openfile->edittop;
1775 filestruct *current_save = openfile->current;
1776 /* Save where we are. */
1777 bool canceled = FALSE;
1778 /* The return value. */
1779 bool case_sens_set = ISSET(CASE_SENSITIVE);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001780#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001781 bool backwards_search_set = ISSET(BACKWARDS_SEARCH);
1782#endif
1783#ifdef HAVE_REGEX_H
1784 bool regexp_set = ISSET(USE_REGEXP);
1785#endif
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001786#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001787 bool old_mark_set = openfile->mark_set;
1788 bool added_magicline = FALSE;
1789 /* Whether we added a magicline after filebot. */
1790 bool right_side_up = FALSE;
1791 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
1792 * FALSE if (current, current_x) is. */
1793 filestruct *top, *bot;
1794 size_t top_x, bot_x;
1795#endif
1796
1797 /* Make sure spell-check is case sensitive. */
1798 SET(CASE_SENSITIVE);
1799
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001800#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001801 /* Make sure spell-check goes forward only. */
1802 UNSET(BACKWARDS_SEARCH);
1803#endif
1804#ifdef HAVE_REGEX_H
1805 /* Make sure spell-check doesn't use regular expressions. */
1806 UNSET(USE_REGEXP);
1807#endif
1808
1809 /* Save the current search/replace strings. */
1810 search_init_globals();
1811 save_search = last_search;
1812 save_replace = last_replace;
1813
1814 /* Set the search/replace strings to the misspelled word. */
1815 last_search = mallocstrcpy(NULL, word);
1816 last_replace = mallocstrcpy(NULL, word);
1817
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001818#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001819 if (old_mark_set) {
1820 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00001821 * contains only the marked text; if the NO_NEWLINES flag isn't
1822 * set, keep track of whether the text will have a magicline
1823 * added when we're done correcting misspelled words; and
1824 * turn the mark off. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001825 mark_order((const filestruct **)&top, &top_x,
1826 (const filestruct **)&bot, &bot_x, &right_side_up);
1827 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00001828 if (!ISSET(NO_NEWLINES))
1829 added_magicline = (openfile->filebot->data[0] != '\0');
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001830 openfile->mark_set = FALSE;
1831 }
1832#endif
1833
1834 /* Start from the top of the file. */
1835 openfile->edittop = openfile->fileage;
1836 openfile->current = openfile->fileage;
1837 openfile->current_x = (size_t)-1;
1838 openfile->placewewant = 0;
1839
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001840 /* Find the first whole occurrence of word. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001841 findnextstr_wrap_reset();
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001842 while (findnextstr(TRUE, FALSE, openfile->fileage, 0, word,
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001843 &match_len)) {
1844 if (is_whole_word(openfile->current_x, openfile->current->data,
1845 word)) {
1846 size_t xpt = xplustabs();
1847 char *exp_word = display_string(openfile->current->data,
1848 xpt, strnlenpt(openfile->current->data,
1849 openfile->current_x + match_len) - xpt, FALSE);
1850
1851 edit_refresh();
1852
1853 do_replace_highlight(TRUE, exp_word);
1854
1855 /* Allow all instances of the word to be corrected. */
David Lawrence Ramsey9d8c2842006-02-07 21:11:05 +00001856 canceled = (do_prompt(FALSE,
1857#ifndef DISABLE_TABCOMP
1858 TRUE,
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001859#endif
Chris Allegretta79a33bb2008-03-05 07:34:01 +00001860 MSPELL, word,
Chris Allegretta10f868d2008-03-14 04:08:51 +00001861 &meta_key, &func_key,
David Lawrence Ramsey9d8c2842006-02-07 21:11:05 +00001862#ifndef NANO_TINY
1863 NULL,
1864#endif
David Lawrence Ramsey68160072006-02-18 21:32:29 +00001865 edit_refresh, _("Edit a replacement")) == -1);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001866
1867 do_replace_highlight(FALSE, exp_word);
1868
1869 free(exp_word);
1870
1871 if (!canceled && strcmp(word, answer) != 0) {
1872 openfile->current_x--;
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001873 do_replace_loop(TRUE, &canceled, openfile->current,
1874 &openfile->current_x, word);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001875 }
1876
1877 break;
1878 }
1879 }
1880
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001881#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001882 if (old_mark_set) {
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00001883 /* If the mark was on, the NO_NEWLINES flag isn't set, and we
1884 * added a magicline, remove it now. */
1885 if (!ISSET(NO_NEWLINES) && added_magicline)
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001886 remove_magicline();
1887
1888 /* Put the beginning and the end of the mark at the beginning
1889 * and the end of the spell-checked text. */
1890 if (openfile->fileage == openfile->filebot)
1891 bot_x += top_x;
1892 if (right_side_up) {
1893 openfile->mark_begin_x = top_x;
1894 current_x_save = bot_x;
1895 } else {
1896 current_x_save = top_x;
1897 openfile->mark_begin_x = bot_x;
1898 }
1899
1900 /* Unpartition the filestruct so that it contains all the text
1901 * again, and turn the mark back on. */
1902 unpartition_filestruct(&filepart);
1903 openfile->mark_set = TRUE;
1904 }
1905#endif
1906
1907 /* Restore the search/replace strings. */
1908 free(last_search);
1909 last_search = save_search;
1910 free(last_replace);
1911 last_replace = save_replace;
1912
1913 /* Restore where we were. */
1914 openfile->edittop = edittop_save;
1915 openfile->current = current_save;
1916 openfile->current_x = current_x_save;
1917 openfile->placewewant = pww_save;
1918
1919 /* Restore case sensitivity setting. */
1920 if (!case_sens_set)
1921 UNSET(CASE_SENSITIVE);
1922
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001923#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001924 /* Restore search/replace direction. */
1925 if (backwards_search_set)
1926 SET(BACKWARDS_SEARCH);
1927#endif
1928#ifdef HAVE_REGEX_H
1929 /* Restore regular expression usage setting. */
1930 if (regexp_set)
1931 SET(USE_REGEXP);
1932#endif
1933
1934 return !canceled;
1935}
1936
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001937/* Internal (integrated) spell checking using the spell program,
1938 * filtered through the sort and uniq programs. Return NULL for normal
1939 * termination, and the error string otherwise. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001940const char *do_int_speller(const char *tempfile_name)
1941{
1942 char *read_buff, *read_buff_ptr, *read_buff_word;
1943 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
1944 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
1945 pid_t pid_spell, pid_sort, pid_uniq;
1946 int spell_status, sort_status, uniq_status;
1947
1948 /* Create all three pipes up front. */
1949 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 ||
1950 pipe(uniq_fd) == -1)
1951 return _("Could not create pipe");
1952
1953 statusbar(_("Creating misspelled word list, please wait..."));
1954
1955 /* A new process to run spell in. */
1956 if ((pid_spell = fork()) == 0) {
David Lawrence Ramseyb159f942006-07-28 17:06:27 +00001957 /* Child continues (i.e. future spell process). */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001958 close(spell_fd[0]);
1959
1960 /* Replace the standard input with the temp file. */
1961 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1962 goto close_pipes_and_exit;
1963
1964 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1965 goto close_pipes_and_exit;
1966
1967 close(tempfile_fd);
1968
1969 /* Send spell's standard output to the pipe. */
1970 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1971 goto close_pipes_and_exit;
1972
1973 close(spell_fd[1]);
1974
David Lawrence Ramsey3239ff22005-11-29 20:01:06 +00001975 /* Start the spell program; we are using $PATH. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001976 execlp("spell", "spell", NULL);
1977
1978 /* This should not be reached if spell is found. */
1979 exit(1);
1980 }
1981
1982 /* Parent continues here. */
1983 close(spell_fd[1]);
1984
1985 /* A new process to run sort in. */
1986 if ((pid_sort = fork()) == 0) {
David Lawrence Ramseyb159f942006-07-28 17:06:27 +00001987 /* Child continues (i.e. future spell process). Replace the
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001988 * standard input with the standard output of the old pipe. */
1989 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1990 goto close_pipes_and_exit;
1991
1992 close(spell_fd[0]);
1993
1994 /* Send sort's standard output to the new pipe. */
1995 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1996 goto close_pipes_and_exit;
1997
1998 close(sort_fd[1]);
1999
2000 /* Start the sort program. Use -f to remove mixed case. If
2001 * this isn't portable, let me know. */
2002 execlp("sort", "sort", "-f", NULL);
2003
2004 /* This should not be reached if sort is found. */
2005 exit(1);
2006 }
2007
2008 close(spell_fd[0]);
2009 close(sort_fd[1]);
2010
2011 /* A new process to run uniq in. */
2012 if ((pid_uniq = fork()) == 0) {
David Lawrence Ramseyb159f942006-07-28 17:06:27 +00002013 /* Child continues (i.e. future uniq process). Replace the
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002014 * standard input with the standard output of the old pipe. */
2015 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
2016 goto close_pipes_and_exit;
2017
2018 close(sort_fd[0]);
2019
2020 /* Send uniq's standard output to the new pipe. */
2021 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2022 goto close_pipes_and_exit;
2023
2024 close(uniq_fd[1]);
2025
2026 /* Start the uniq program; we are using PATH. */
2027 execlp("uniq", "uniq", NULL);
2028
2029 /* This should not be reached if uniq is found. */
2030 exit(1);
2031 }
2032
2033 close(sort_fd[0]);
2034 close(uniq_fd[1]);
2035
2036 /* The child process was not forked successfully. */
2037 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
2038 close(uniq_fd[0]);
2039 return _("Could not fork");
2040 }
2041
2042 /* Get the system pipe buffer size. */
2043 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
2044 close(uniq_fd[0]);
2045 return _("Could not get size of pipe buffer");
2046 }
2047
2048 /* Read in the returned spelling errors. */
2049 read_buff_read = 0;
2050 read_buff_size = pipe_buff_size + 1;
2051 read_buff = read_buff_ptr = charalloc(read_buff_size);
2052
2053 while ((bytesread = read(uniq_fd[0], read_buff_ptr,
2054 pipe_buff_size)) > 0) {
2055 read_buff_read += bytesread;
2056 read_buff_size += pipe_buff_size;
2057 read_buff = read_buff_ptr = charealloc(read_buff,
2058 read_buff_size);
2059 read_buff_ptr += read_buff_read;
2060 }
2061
2062 *read_buff_ptr = '\0';
2063 close(uniq_fd[0]);
2064
2065 /* Process the spelling errors. */
2066 read_buff_word = read_buff_ptr = read_buff;
2067
2068 while (*read_buff_ptr != '\0') {
2069 if ((*read_buff_ptr == '\r') || (*read_buff_ptr == '\n')) {
2070 *read_buff_ptr = '\0';
2071 if (read_buff_word != read_buff_ptr) {
2072 if (!do_int_spell_fix(read_buff_word)) {
2073 read_buff_word = read_buff_ptr;
2074 break;
2075 }
2076 }
2077 read_buff_word = read_buff_ptr + 1;
2078 }
2079 read_buff_ptr++;
2080 }
2081
2082 /* Special case: the last word doesn't end with '\r' or '\n'. */
2083 if (read_buff_word != read_buff_ptr)
2084 do_int_spell_fix(read_buff_word);
2085
2086 free(read_buff);
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002087 search_replace_abort();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002088 edit_refresh();
2089
2090 /* Process the end of the spell process. */
2091 waitpid(pid_spell, &spell_status, 0);
2092 waitpid(pid_sort, &sort_status, 0);
2093 waitpid(pid_uniq, &uniq_status, 0);
2094
2095 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
2096 return _("Error invoking \"spell\"");
2097
2098 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
2099 return _("Error invoking \"sort -f\"");
2100
2101 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
2102 return _("Error invoking \"uniq\"");
2103
2104 /* Otherwise... */
2105 return NULL;
2106
2107 close_pipes_and_exit:
2108 /* Don't leak any handles. */
2109 close(tempfile_fd);
2110 close(spell_fd[0]);
2111 close(spell_fd[1]);
2112 close(sort_fd[0]);
2113 close(sort_fd[1]);
2114 close(uniq_fd[0]);
2115 close(uniq_fd[1]);
2116 exit(1);
2117}
2118
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002119/* External (alternate) spell checking. Return NULL for normal
2120 * termination, and the error string otherwise. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002121const char *do_alt_speller(char *tempfile_name)
2122{
2123 int alt_spell_status;
2124 size_t current_x_save = openfile->current_x;
2125 size_t pww_save = openfile->placewewant;
2126 ssize_t current_y_save = openfile->current_y;
2127 ssize_t lineno_save = openfile->current->lineno;
2128 pid_t pid_spell;
2129 char *ptr;
2130 static int arglen = 3;
2131 static char **spellargs = NULL;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002132#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002133 bool old_mark_set = openfile->mark_set;
2134 bool added_magicline = FALSE;
2135 /* Whether we added a magicline after filebot. */
2136 bool right_side_up = FALSE;
2137 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
2138 * FALSE if (current, current_x) is. */
2139 filestruct *top, *bot;
2140 size_t top_x, bot_x;
2141 ssize_t mb_lineno_save = 0;
2142 /* We're going to close the current file, and open the output of
2143 * the alternate spell command. The line that mark_begin points
2144 * to will be freed, so we save the line number and restore it
2145 * afterwards. */
2146 size_t totsize_save = openfile->totsize;
2147 /* Our saved value of totsize, used when we spell-check a marked
2148 * selection. */
2149
2150 if (old_mark_set) {
2151 /* If the mark is on, save the number of the line it starts on,
2152 * and then turn the mark off. */
2153 mb_lineno_save = openfile->mark_begin->lineno;
2154 openfile->mark_set = FALSE;
2155 }
2156#endif
2157
2158 endwin();
2159
2160 /* Set up an argument list to pass execvp(). */
2161 if (spellargs == NULL) {
2162 spellargs = (char **)nmalloc(arglen * sizeof(char *));
2163
2164 spellargs[0] = strtok(alt_speller, " ");
2165 while ((ptr = strtok(NULL, " ")) != NULL) {
2166 arglen++;
2167 spellargs = (char **)nrealloc(spellargs, arglen *
2168 sizeof(char *));
2169 spellargs[arglen - 3] = ptr;
2170 }
2171 spellargs[arglen - 1] = NULL;
2172 }
2173 spellargs[arglen - 2] = tempfile_name;
2174
2175 /* Start a new process for the alternate speller. */
2176 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey2e2112c2005-11-29 05:39:31 +00002177 /* Start alternate spell program; we are using $PATH. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002178 execvp(spellargs[0], spellargs);
2179
2180 /* Should not be reached, if alternate speller is found!!! */
2181 exit(1);
2182 }
2183
2184 /* If we couldn't fork, get out. */
2185 if (pid_spell < 0)
2186 return _("Could not fork");
2187
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002188#ifndef NANO_TINY
David Lawrence Ramseyb18482e2005-07-26 00:06:34 +00002189 /* Don't handle a pending SIGWINCH until the alternate spell checker
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002190 * is finished and we've loaded the spell-checked file back in. */
David Lawrence Ramseyb18482e2005-07-26 00:06:34 +00002191 allow_pending_sigwinch(FALSE);
2192#endif
2193
2194 /* Wait for the alternate spell checker to finish. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002195 wait(&alt_spell_status);
2196
David Lawrence Ramsey84fdb902005-08-14 20:08:49 +00002197 /* Reenter curses mode. */
2198 doupdate();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002199
2200 /* Restore the terminal to its previous state. */
2201 terminal_init();
2202
2203 /* Turn the cursor back on for sure. */
2204 curs_set(1);
2205
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002206 /* The screen might have been resized. If it has, reinitialize all
2207 * the windows based on the new screen dimensions. */
2208 window_init();
2209
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002210 if (!WIFEXITED(alt_spell_status) ||
2211 WEXITSTATUS(alt_spell_status) != 0) {
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002212 char *alt_spell_error;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002213 char *invoke_error = _("Error invoking \"%s\"");
2214
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002215#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002216 /* Turn the mark back on if it was on before. */
2217 openfile->mark_set = old_mark_set;
2218#endif
2219
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002220 alt_spell_error =
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002221 charalloc(strlen(invoke_error) +
2222 strlen(alt_speller) + 1);
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002223 sprintf(alt_spell_error, invoke_error, alt_speller);
2224 return alt_spell_error;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002225 }
2226
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002227#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002228 if (old_mark_set) {
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002229 /* If the mark is on, partition the filestruct so that it
2230 * contains only the marked text; if the NO_NEWLINES flag isn't
2231 * set, keep track of whether the text will have a magicline
2232 * added when we're done correcting misspelled words; and
2233 * turn the mark off. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002234 mark_order((const filestruct **)&top, &top_x,
2235 (const filestruct **)&bot, &bot_x, &right_side_up);
2236 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002237 if (!ISSET(NO_NEWLINES))
2238 added_magicline = (openfile->filebot->data[0] != '\0');
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002239
2240 /* Get the number of characters in the marked text, and subtract
2241 * it from the saved value of totsize. */
2242 totsize_save -= get_totsize(top, bot);
2243 }
2244#endif
2245
David Lawrence Ramsey9c984e82005-11-08 19:15:58 +00002246 /* Replace the text of the current buffer with the spell-checked
2247 * text. */
2248 replace_buffer(tempfile_name);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002249
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002250#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002251 if (old_mark_set) {
2252 filestruct *top_save = openfile->fileage;
2253
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002254 /* If the mark was on, the NO_NEWLINES flag isn't set, and we
2255 * added a magicline, remove it now. */
2256 if (!ISSET(NO_NEWLINES) && added_magicline)
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002257 remove_magicline();
2258
2259 /* Put the beginning and the end of the mark at the beginning
2260 * and the end of the spell-checked text. */
2261 if (openfile->fileage == openfile->filebot)
2262 bot_x += top_x;
2263 if (right_side_up) {
2264 openfile->mark_begin_x = top_x;
2265 current_x_save = bot_x;
2266 } else {
2267 current_x_save = top_x;
2268 openfile->mark_begin_x = bot_x;
2269 }
2270
2271 /* Unpartition the filestruct so that it contains all the text
2272 * again. Note that we've replaced the marked text originally
2273 * in the partition with the spell-checked marked text in the
2274 * temp file. */
2275 unpartition_filestruct(&filepart);
2276
2277 /* Renumber starting with the beginning line of the old
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002278 * partition. Also add the number of characters in the
2279 * spell-checked marked text to the saved value of totsize, and
2280 * then make that saved value the actual value. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002281 renumber(top_save);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002282 totsize_save += openfile->totsize;
2283 openfile->totsize = totsize_save;
2284
2285 /* Assign mark_begin to the line where the mark began before. */
2286 do_gotopos(mb_lineno_save, openfile->mark_begin_x,
2287 current_y_save, 0);
2288 openfile->mark_begin = openfile->current;
2289
2290 /* Assign mark_begin_x to the location in mark_begin where the
2291 * mark began before, adjusted for any shortening of the
2292 * line. */
2293 openfile->mark_begin_x = openfile->current_x;
2294
2295 /* Turn the mark back on. */
2296 openfile->mark_set = TRUE;
2297 }
2298#endif
2299
2300 /* Go back to the old position, and mark the file as modified. */
2301 do_gotopos(lineno_save, current_x_save, current_y_save, pww_save);
2302 set_modified();
2303
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002304#ifndef NANO_TINY
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002305 /* Handle a pending SIGWINCH again. */
2306 allow_pending_sigwinch(TRUE);
2307#endif
2308
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002309 return NULL;
2310}
2311
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002312/* Spell check the current file. If an alternate spell checker is
2313 * specified, use it. Otherwise, use the internal spell checker. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002314void do_spell(void)
2315{
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002316 bool status;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002317 FILE *temp_file;
2318 char *temp = safe_tempfile(&temp_file);
2319 const char *spell_msg;
2320
2321 if (temp == NULL) {
David Lawrence Ramseyf0e3ca62006-05-03 13:11:00 +00002322 statusbar(_("Error writing temp file: %s"), strerror(errno));
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002323 return;
2324 }
2325
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002326 status =
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002327#ifndef NANO_TINY
David Lawrence Ramsey0e1df432007-01-12 02:58:12 +00002328 openfile->mark_set ? write_marked_file(temp, temp_file, TRUE,
David Lawrence Ramseyb6c4dbf2006-11-25 22:38:17 +00002329 OVERWRITE) :
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002330#endif
David Lawrence Ramseyb6c4dbf2006-11-25 22:38:17 +00002331 write_file(temp, temp_file, TRUE, OVERWRITE, FALSE);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002332
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002333 if (!status) {
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002334 statusbar(_("Error writing temp file: %s"), strerror(errno));
2335 free(temp);
2336 return;
2337 }
2338
2339 spell_msg = (alt_speller != NULL) ? do_alt_speller(temp) :
2340 do_int_speller(temp);
2341 unlink(temp);
2342 free(temp);
2343
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002344 currmenu = MMAIN;
David Lawrence Ramseyf32e1dd2006-06-09 17:09:51 +00002345
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002346 /* If the spell-checker printed any error messages onscreen, make
2347 * sure that they're cleared off. */
David Lawrence Ramseyf32e1dd2006-06-09 17:09:51 +00002348 total_refresh();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002349
2350 if (spell_msg != NULL) {
2351 if (errno == 0)
2352 /* Don't display an error message of "Success". */
2353 statusbar(_("Spell checking failed: %s"), spell_msg);
2354 else
2355 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
2356 strerror(errno));
2357 } else
2358 statusbar(_("Finished checking spelling"));
2359}
2360#endif /* !DISABLE_SPELLER */
2361
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002362#ifndef NANO_TINY
David Lawrence Ramseyd7f0fe92005-08-10 22:51:49 +00002363/* Our own version of "wc". Note that its character counts are in
2364 * multibyte characters instead of single-byte characters. */
David Lawrence Ramsey8e942342005-07-25 04:21:46 +00002365void do_wordlinechar_count(void)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002366{
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002367 size_t words = 0, chars = 0;
Chris Allegretta8b6461f2008-05-31 23:09:40 +00002368 ssize_t nlines = 0;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002369 size_t current_x_save = openfile->current_x;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002370 size_t pww_save = openfile->placewewant;
2371 filestruct *current_save = openfile->current;
2372 bool old_mark_set = openfile->mark_set;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002373 filestruct *top, *bot;
2374 size_t top_x, bot_x;
2375
2376 if (old_mark_set) {
2377 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +00002378 * contains only the marked text, and turn the mark off. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002379 mark_order((const filestruct **)&top, &top_x,
2380 (const filestruct **)&bot, &bot_x, NULL);
2381 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002382 openfile->mark_set = FALSE;
2383 }
2384
2385 /* Start at the top of the file. */
2386 openfile->current = openfile->fileage;
2387 openfile->current_x = 0;
2388 openfile->placewewant = 0;
2389
2390 /* Keep moving to the next word (counting punctuation characters as
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002391 * part of a word, as "wc -w" does), without updating the screen,
2392 * until we reach the end of the file, incrementing the total word
2393 * count whenever we're on a word just before moving. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002394 while (openfile->current != openfile->filebot ||
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +00002395 openfile->current->data[openfile->current_x] != '\0') {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002396 if (do_next_word(TRUE, FALSE))
2397 words++;
2398 }
2399
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002400 /* Get the total line and character counts, as "wc -l" and "wc -c"
2401 * do, but get the latter in multibyte characters. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002402 if (old_mark_set) {
Chris Allegretta8b6461f2008-05-31 23:09:40 +00002403 nlines = openfile->filebot->lineno -
David Lawrence Ramsey78a81b22005-07-25 18:59:24 +00002404 openfile->fileage->lineno + 1;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002405 chars = get_totsize(openfile->fileage, openfile->filebot);
2406
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002407 /* Unpartition the filestruct so that it contains all the text
2408 * again, and turn the mark back on. */
2409 unpartition_filestruct(&filepart);
2410 openfile->mark_set = TRUE;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002411 } else {
Chris Allegretta8b6461f2008-05-31 23:09:40 +00002412 nlines = openfile->filebot->lineno;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002413 chars = openfile->totsize;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002414 }
2415
2416 /* Restore where we were. */
2417 openfile->current = current_save;
2418 openfile->current_x = current_x_save;
2419 openfile->placewewant = pww_save;
2420
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002421 /* Display the total word, line, and character counts on the
2422 * statusbar. */
David Lawrence Ramsey7b71f572005-10-06 20:46:11 +00002423 statusbar(_("%sWords: %lu Lines: %ld Chars: %lu"), old_mark_set ?
Chris Allegretta8b6461f2008-05-31 23:09:40 +00002424 _("In Selection: ") : "", (unsigned long)words, (long)nlines,
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002425 (unsigned long)chars);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002426}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002427#endif /* !NANO_TINY */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002428
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002429/* Get verbatim input. */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002430void do_verbatim_input(void)
2431{
2432 int *kbinput;
2433 size_t kbinput_len, i;
2434 char *output;
2435
David Lawrence Ramseyf451d6a2006-05-27 16:02:48 +00002436 /* TRANSLATORS: This is displayed when the next keystroke will be
2437 * inserted verbatim. */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002438 statusbar(_("Verbatim Input"));
2439
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002440 /* Read in all the verbatim characters. */
2441 kbinput = get_verbatim_kbinput(edit, &kbinput_len);
2442
David Lawrence Ramseya620e682006-05-27 18:19:03 +00002443 /* If constant cursor position display is on, make sure the current
2444 * cursor position will be properly displayed on the statusbar.
2445 * Otherwise, blank the statusbar. */
2446 if (ISSET(CONST_UPDATE))
2447 do_cursorpos(TRUE);
2448 else {
2449 blank_statusbar();
2450 wnoutrefresh(bottomwin);
2451 }
David Lawrence Ramsey6fb66892006-05-27 17:39:19 +00002452
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002453 /* Display all the verbatim characters at once, not filtering out
2454 * control characters. */
2455 output = charalloc(kbinput_len + 1);
2456
2457 for (i = 0; i < kbinput_len; i++)
2458 output[i] = (char)kbinput[i];
2459 output[i] = '\0';
2460
David Lawrence Ramseyad36bdc2006-12-02 17:22:21 +00002461 free(kbinput);
2462
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002463 do_output(output, kbinput_len, TRUE);
2464
2465 free(output);
2466}