blob: 332abb1e13b189f3e608348c4f12d8496d1912ee [file] [log] [blame]
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001/* $Id$ */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002/**************************************************************************
David Lawrence Ramsey4005fc62005-10-08 06:12:41 +00003 * text.c *
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00004 * *
Chris Allegretta8a07a962009-12-02 03:36:22 +00005 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
6 * 2008, 2009 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
Chris Allegretta07fcc4c2008-07-10 20:13:04 +000073#ifndef NANO_TINY
Chris Allegretta14c86202008-08-03 04:48:05 +000074 update_undo(DEL);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +000075#endif
76
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000077 assert(openfile->current != NULL && openfile->current->data != NULL && openfile->current_x <= strlen(openfile->current->data));
78
79 openfile->placewewant = xplustabs();
80
81 if (openfile->current->data[openfile->current_x] != '\0') {
82 int char_buf_len = parse_mbchar(openfile->current->data +
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +000083 openfile->current_x, NULL, NULL);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000084 size_t line_len = strlen(openfile->current->data +
85 openfile->current_x);
86
87 assert(openfile->current_x < strlen(openfile->current->data));
88
89 /* Let's get dangerous. */
90 charmove(&openfile->current->data[openfile->current_x],
91 &openfile->current->data[openfile->current_x +
92 char_buf_len], line_len - char_buf_len + 1);
93
94 null_at(&openfile->current->data, openfile->current_x +
95 line_len - char_buf_len);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000096#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000097 if (openfile->mark_set && openfile->mark_begin ==
98 openfile->current && openfile->current_x <
99 openfile->mark_begin_x)
100 openfile->mark_begin_x -= char_buf_len;
101#endif
102 openfile->totsize--;
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000103 } else if (openfile->current != openfile->filebot) {
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000104 filestruct *foo = openfile->current->next;
105
106 assert(openfile->current_x == strlen(openfile->current->data));
107
108 /* If we're deleting at the end of a line, we need to call
109 * edit_refresh(). */
110 if (openfile->current->data[openfile->current_x] == '\0')
111 do_refresh = TRUE;
112
113 openfile->current->data = charealloc(openfile->current->data,
114 openfile->current_x + strlen(foo->data) + 1);
115 strcpy(openfile->current->data + openfile->current_x,
116 foo->data);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000117#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000118 if (openfile->mark_set && openfile->mark_begin ==
119 openfile->current->next) {
120 openfile->mark_begin = openfile->current;
121 openfile->mark_begin_x += openfile->current_x;
122 }
123#endif
124 if (openfile->filebot == foo)
125 openfile->filebot = openfile->current;
126
127 unlink_node(foo);
128 delete_node(foo);
129 renumber(openfile->current);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000130 openfile->totsize--;
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000131
David Lawrence Ramseya0168ca2005-11-05 17:35:44 +0000132 /* If the NO_NEWLINES flag isn't set, and text has been added to
133 * the magicline as a result of deleting at the end of the line
David Lawrence Ramsey0f6236f2005-11-09 00:08:29 +0000134 * before filebot, add a new magicline. */
David Lawrence Ramseya0168ca2005-11-05 17:35:44 +0000135 if (!ISSET(NO_NEWLINES) && openfile->current ==
136 openfile->filebot && openfile->current->data[0] != '\0')
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000137 new_magicline();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000138 } else
139 return;
140
David Lawrence Ramsey0f6236f2005-11-09 00:08:29 +0000141 set_modified();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000142
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000143 if (do_refresh)
Chris Allegrettafd265af2009-02-06 03:41:02 +0000144 edit_refresh_needed = TRUE;
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000145 else
146 update_line(openfile->current, openfile->current_x);
147}
148
David Lawrence Ramsey5b7b3e32005-12-31 21:22:54 +0000149/* Backspace over one character. That is, move the cursor left one
David Lawrence Ramsey84d22e32006-11-08 13:05:50 +0000150 * character, and then delete the character under the cursor. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000151void do_backspace(void)
152{
153 if (openfile->current != openfile->fileage ||
154 openfile->current_x > 0) {
David Lawrence Ramsey1c3bfa92005-09-13 04:53:44 +0000155 do_left();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000156 do_delete();
157 }
158}
159
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000160/* Insert a tab. If the TABS_TO_SPACES flag is set, insert the number
161 * of spaces that a tab would normally take up. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000162void do_tab(void)
163{
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000164#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000165 if (ISSET(TABS_TO_SPACES)) {
166 char *output;
David Lawrence Ramsey90b07fc2005-10-07 15:57:48 +0000167 size_t output_len = 0, new_pww = xplustabs();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000168
169 do {
170 new_pww++;
171 output_len++;
172 } while (new_pww % tabsize != 0);
173
174 output = charalloc(output_len + 1);
175
176 charset(output, ' ', output_len);
177 output[output_len] = '\0';
178
179 do_output(output, output_len, TRUE);
180
181 free(output);
182 } else {
183#endif
Chris Allegretta5a018f02009-11-29 06:13:22 +0000184 do_output((char *) "\t", 1, TRUE);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000185#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000186 }
187#endif
188}
189
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000190#ifndef NANO_TINY
David Lawrence Ramseye44cd2d2007-01-11 22:54:55 +0000191/* Indent or unindent the current line (or, if the mark is on, all lines
192 * covered by the mark) len columns, depending on whether len is
193 * positive or negative. If the TABS_TO_SPACES flag is set, indent or
194 * unindent by len spaces. Otherwise, indent or unindent by (len /
195 * tabsize) tabs and (len % tabsize) spaces. */
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000196void do_indent(ssize_t cols)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000197{
198 bool indent_changed = FALSE;
199 /* Whether any indenting or unindenting was done. */
200 bool unindent = FALSE;
201 /* Whether we're unindenting text. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000202 char *line_indent = NULL;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000203 /* The text added to each line in order to indent it. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000204 size_t line_indent_len = 0;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000205 /* The length of the text added to each line in order to indent
206 * it. */
207 filestruct *top, *bot, *f;
208 size_t top_x, bot_x;
209
210 assert(openfile->current != NULL && openfile->current->data != NULL);
211
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000212 /* If cols is zero, get out. */
213 if (cols == 0)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000214 return;
215
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000216 /* If cols is negative, make it positive and set unindent to
217 * TRUE. */
218 if (cols < 0) {
219 cols = -cols;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000220 unindent = TRUE;
221 /* Otherwise, we're indenting, in which case the file will always be
222 * modified, so set indent_changed to TRUE. */
223 } else
224 indent_changed = TRUE;
225
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000226 /* If the mark is on, use all lines covered by the mark. */
227 if (openfile->mark_set)
228 mark_order((const filestruct **)&top, &top_x,
229 (const filestruct **)&bot, &bot_x, NULL);
230 /* Otherwise, use the current line. */
231 else {
232 top = openfile->current;
233 bot = top;
234 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000235
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000236 if (!unindent) {
237 /* Set up the text we'll be using as indentation. */
238 line_indent = charalloc(cols + 1);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000239
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000240 if (ISSET(TABS_TO_SPACES)) {
241 /* Set the indentation to cols spaces. */
242 charset(line_indent, ' ', cols);
243 line_indent_len = cols;
244 } else {
245 /* Set the indentation to (cols / tabsize) tabs and (cols %
246 * tabsize) spaces. */
247 size_t num_tabs = cols / tabsize;
248 size_t num_spaces = cols % tabsize;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000249
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000250 charset(line_indent, '\t', num_tabs);
251 charset(line_indent + num_tabs, ' ', num_spaces);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000252
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000253 line_indent_len = num_tabs + num_spaces;
254 }
255
256 line_indent[line_indent_len] = '\0';
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000257 }
258
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000259 /* Go through each line of the text. */
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000260 for (f = top; f != bot->next; f = f->next) {
261 size_t line_len = strlen(f->data);
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000262 size_t indent_len = indent_length(f->data);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000263
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000264 if (!unindent) {
265 /* If we're indenting, add the characters in line_indent to
266 * the beginning of the non-whitespace text of this line. */
267 f->data = charealloc(f->data, line_len +
268 line_indent_len + 1);
269 charmove(&f->data[indent_len + line_indent_len],
270 &f->data[indent_len], line_len - indent_len + 1);
271 strncpy(f->data + indent_len, line_indent, line_indent_len);
272 openfile->totsize += line_indent_len;
273
274 /* Keep track of the change in the current line. */
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000275 if (openfile->mark_set && f == openfile->mark_begin &&
276 openfile->mark_begin_x >= indent_len)
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000277 openfile->mark_begin_x += line_indent_len;
278
279 if (f == openfile->current && openfile->current_x >=
280 indent_len)
281 openfile->current_x += line_indent_len;
282
283 /* If the NO_NEWLINES flag isn't set, and this is the
284 * magicline, add a new magicline. */
285 if (!ISSET(NO_NEWLINES) && f == openfile->filebot)
286 new_magicline();
287 } else {
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000288 size_t indent_col = strnlenpt(f->data, indent_len);
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000289 /* The length in columns of the indentation on this
290 * line. */
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000291
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000292 if (cols <= indent_col) {
293 size_t indent_new = actual_x(f->data, indent_col -
294 cols);
David Lawrence Ramsey5bb77272006-05-06 14:37:33 +0000295 /* The length of the indentation remaining on
296 * this line after we unindent. */
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000297 size_t indent_shift = indent_len - indent_new;
David Lawrence Ramsey5bb77272006-05-06 14:37:33 +0000298 /* The change in the indentation on this line
299 * after we unindent. */
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000300
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000301 /* If we're unindenting, and there's at least cols
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000302 * columns' worth of indentation at the beginning of the
303 * non-whitespace text of this line, remove it. */
304 charmove(&f->data[indent_new], &f->data[indent_len],
305 line_len - indent_shift - indent_new + 1);
306 null_at(&f->data, line_len - indent_shift + 1);
307 openfile->totsize -= indent_shift;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000308
David Lawrence Ramsey2e8fac62006-04-29 15:44:58 +0000309 /* Keep track of the change in the current line. */
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000310 if (openfile->mark_set && f == openfile->mark_begin &&
David Lawrence Ramseyeb4f90e2006-05-05 14:22:42 +0000311 openfile->mark_begin_x > indent_new) {
312 if (openfile->mark_begin_x <= indent_len)
313 openfile->mark_begin_x = indent_new;
314 else
315 openfile->mark_begin_x -= indent_shift;
316 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000317
David Lawrence Ramseyac37b042006-05-03 12:59:05 +0000318 if (f == openfile->current && openfile->current_x >
David Lawrence Ramseyeb4f90e2006-05-05 14:22:42 +0000319 indent_new) {
320 if (openfile->current_x <= indent_len)
321 openfile->current_x = indent_new;
322 else
323 openfile->current_x -= indent_shift;
324 }
David Lawrence Ramsey7194a612006-04-29 16:11:21 +0000325
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000326 /* We've unindented, so set indent_changed to TRUE. */
327 if (!indent_changed)
328 indent_changed = TRUE;
329 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000330 }
331 }
332
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000333 if (!unindent)
David Lawrence Ramsey25456862006-05-05 15:43:52 +0000334 /* Clean up. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000335 free(line_indent);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000336
337 if (indent_changed) {
338 /* Mark the file as modified. */
339 set_modified();
340
341 /* Update the screen. */
Chris Allegrettafd265af2009-02-06 03:41:02 +0000342 edit_refresh_needed = TRUE;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000343 }
344}
345
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000346/* Indent the current line, or all lines covered by the mark if the mark
347 * is on, tabsize columns. */
348void do_indent_void(void)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000349{
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000350 do_indent(tabsize);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000351}
352
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000353/* Unindent the current line, or all lines covered by the mark if the
354 * mark is on, tabsize columns. */
355void do_unindent(void)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000356{
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000357 do_indent(-tabsize);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000358}
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000359
Chris Allegrettab549f372008-09-16 21:35:19 +0000360/* undo a cut, or re-do an uncut */
361void undo_cut(undo *u)
362{
Chris Allegretta42726f72009-07-27 04:16:44 +0000363 /* If we cut the magicline may was well not crash :/ */
364 if (!u->cutbuffer)
365 return;
Chris Allegrettab549f372008-09-16 21:35:19 +0000366
Chris Allegretta42726f72009-07-27 04:16:44 +0000367 cutbuffer = copy_filestruct(u->cutbuffer);
Chris Allegrettab549f372008-09-16 21:35:19 +0000368
Chris Allegretta42726f72009-07-27 04:16:44 +0000369 /* Compute cutbottom for the uncut using out copy */
370 for (cutbottom = cutbuffer; cutbottom->next != NULL; cutbottom = cutbottom->next)
371 ;
Chris Allegrettab549f372008-09-16 21:35:19 +0000372
Chris Allegretta42726f72009-07-27 04:16:44 +0000373 /* Get to where we need to uncut from */
374 if (u->mark_set && u->mark_begin_lineno < u->lineno)
375 do_gotolinecolumn(u->mark_begin_lineno, u->mark_begin_x+1, FALSE, FALSE, FALSE, FALSE);
376 else
377 do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
378
379 copy_from_filestruct(cutbuffer, cutbottom);
380 free_filestruct(cutbuffer);
381 cutbuffer = NULL;
Chris Allegrettab549f372008-09-16 21:35:19 +0000382
383}
384
385/* Re-do a cut, or undo an uncut */
386void redo_cut(undo *u) {
387 int i;
Chris Allegrettac81cf522008-10-14 04:34:56 +0000388 filestruct *t, *c;
Chris Allegrettab549f372008-09-16 21:35:19 +0000389
Chris Allegretta42726f72009-07-27 04:16:44 +0000390 /* If we cut the magicline may was well not crash :/ */
391 if (!u->cutbuffer)
392 return;
Chris Allegrettab549f372008-09-16 21:35:19 +0000393
Chris Allegretta42726f72009-07-27 04:16:44 +0000394 do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
395 openfile->mark_set = u->mark_set;
396 if (cutbuffer)
397 free(cutbuffer);
398 cutbuffer = NULL;
399
400 /* Move ahead the same # lines we had if a marked cut */
401 if (u->mark_set) {
402 for (i = 1, t = openfile->fileage; i != u->mark_begin_lineno; i++)
403 t = t->next;
404 openfile->mark_begin = t;
405 } else if (!u->to_end) {
406 /* Here we have a regular old potentially multi-line ^K cut. We'll
407 need to trick nano into thinking it's a marked cut to cut more
408 than one line again */
409 for (c = u->cutbuffer, t = openfile->current; c->next != NULL && t->next != NULL; ) {
Chris Allegrettab549f372008-09-16 21:35:19 +0000410
411#ifdef DEBUG
Chris Allegretta6f083322009-11-11 06:00:33 +0000412 fprintf(stderr, "Advancing, lineno = %lu, data = \"%s\"\n", (unsigned long) t->lineno, t->data);
Chris Allegrettab549f372008-09-16 21:35:19 +0000413#endif
Chris Allegretta42726f72009-07-27 04:16:44 +0000414 c = c->next;
415 t = t->next;
416 }
417 openfile->mark_begin = t;
418 openfile->mark_begin_x = 0;
419 openfile->mark_set = TRUE;
420 }
Chris Allegrettab549f372008-09-16 21:35:19 +0000421
Chris Allegretta42726f72009-07-27 04:16:44 +0000422 openfile->mark_begin_x = u->mark_begin_x;
423 do_cut_text(FALSE, u->to_end, TRUE);
424 openfile->mark_set = FALSE;
425 openfile->mark_begin = NULL;
426 openfile->mark_begin_x = 0;
427 edit_refresh_needed = TRUE;
Chris Allegrettab549f372008-09-16 21:35:19 +0000428}
429
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000430/* Undo the last thing(s) we did */
431void do_undo(void)
432{
433 undo *u = openfile->current_undo;
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000434 filestruct *f = openfile->current, *t;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000435 int len = 0;
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000436 char *undidmsg, *data;
Chris Allegretta14c86202008-08-03 04:48:05 +0000437 filestruct *oldcutbuffer = cutbuffer, *oldcutbottom = cutbottom;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000438
439 if (!u) {
440 statusbar(_("Nothing in undo buffer!"));
441 return;
442 }
443
444
445 if (u->lineno <= f->lineno)
446 for (; f->prev != NULL && f->lineno != u->lineno; f = f->prev)
447 ;
448 else
449 for (; f->next != NULL && f->lineno != u->lineno; f = f->next)
450 ;
451 if (f->lineno != u->lineno) {
Chris Allegretta77bf1b52008-08-21 04:21:06 +0000452 statusbar(_("Internal error: can't match line %d. Please save your work"), u->lineno);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000453 return;
454 }
455#ifdef DEBUG
456 fprintf(stderr, "data we're about to undo = \"%s\"\n", f->data);
457 fprintf(stderr, "Undo running for type %d\n", u->type);
458#endif
459
Chris Allegrettafa406942008-07-13 16:44:19 +0000460 openfile->current_x = u->begin;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000461 switch(u->type) {
462 case ADD:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000463 undidmsg = _("text add");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000464 len = strlen(f->data) - strlen(u->strdata) + 1;
465 data = charalloc(len);
466 strncpy(data, f->data, u->begin);
467 strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]);
468 free(f->data);
469 f->data = data;
470 break;
471 case DEL:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000472 undidmsg = _("text delete");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000473 len = strlen(f->data) + strlen(u->strdata) + 1;
474 data = charalloc(len);
475
476 strncpy(data, f->data, u->begin);
477 strcpy(&data[u->begin], u->strdata);
478 strcpy(&data[u->begin + strlen(u->strdata)], &f->data[u->begin]);
479 free(f->data);
480 f->data = data;
Chris Allegretta0b499d42008-07-14 07:18:22 +0000481 if (u->xflags == UNDO_DEL_BACKSPACE)
482 openfile->current_x += strlen(u->strdata);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000483 break;
484 case SPLIT:
Chris Allegrettab843a512009-04-21 05:34:08 +0000485 undidmsg = _("line wrap");
Chris Allegretta5a018f02009-11-29 06:13:22 +0000486 f->data = (char *) nrealloc(f->data, strlen(f->data) + strlen(u->strdata) + 1);
Chris Allegrettadf543e72009-04-12 06:13:16 +0000487 strcpy(&f->data[strlen(f->data) - 1], u->strdata);
Chris Allegretta8b9fb362009-04-29 04:43:58 +0000488 if (u->strdata2 != NULL)
489 f->next->data = mallocstrcpy(f->next->data, u->strdata2);
490 else {
Chris Allegretta12ba5572009-03-26 01:01:48 +0000491 filestruct *foo = openfile->current->next;
492 unlink_node(foo);
493 delete_node(foo);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000494 }
Chris Allegretta0b499d42008-07-14 07:18:22 +0000495 renumber(f);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000496 break;
497 case UNSPLIT:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000498 undidmsg = _("line join");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000499 t = make_new_node(f);
500 t->data = mallocstrcpy(NULL, u->strdata);
501 data = mallocstrncpy(NULL, f->data, u->begin);
502 data[u->begin] = '\0';
503 free(f->data);
504 f->data = data;
505 splice_node(f, t, f->next);
Chris Allegretta0b499d42008-07-14 07:18:22 +0000506 renumber(f);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000507 break;
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000508 case CUT:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000509 undidmsg = _("text cut");
Chris Allegrettab549f372008-09-16 21:35:19 +0000510 undo_cut(u);
511 break;
512 case UNCUT:
513 undidmsg = _("text uncut");
514 redo_cut(u);
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000515 break;
Chris Allegrettab843a512009-04-21 05:34:08 +0000516 case ENTER:
517 undidmsg = _("line break");
518 if (f->next) {
Chris Allegrettaad37e672009-07-12 03:36:58 +0000519 filestruct *foo = f->next;
Chris Allegretta5a018f02009-11-29 06:13:22 +0000520 f->data = (char *) nrealloc(f->data, strlen(f->data) + strlen(f->next->data) + 1);
Chris Allegrettab843a512009-04-21 05:34:08 +0000521 strcat(f->data, f->next->data);
Chris Allegrettab843a512009-04-21 05:34:08 +0000522 unlink_node(foo);
523 delete_node(foo);
524 }
525 break;
Chris Allegretta14c86202008-08-03 04:48:05 +0000526 case INSERT:
527 undidmsg = _("text insert");
528 cutbuffer = NULL;
529 cutbottom = NULL;
530 /* When we updated mark_begin_lineno in update_undo, it was effectively how many line
531 were inserted due to being partitioned before read_file was called. So we
532 add its value here */
533 openfile->mark_begin = fsfromline(u->lineno + u->mark_begin_lineno - 1);
534 openfile->mark_begin_x = 0;
535 openfile->mark_set = TRUE;
536 do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
537 cut_marked();
538 u->cutbuffer = cutbuffer;
539 u->cutbottom = cutbottom;
540 cutbuffer = oldcutbuffer;
541 cutbottom = oldcutbottom;
542 openfile->mark_set = FALSE;
543 break;
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000544 case REPLACE:
545 undidmsg = _("text replace");
546 data = u->strdata;
547 u->strdata = f->data;
548 f->data = data;
549 break;
Chris Allegrettab843a512009-04-21 05:34:08 +0000550
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000551 default:
Chris Allegretta77bf1b52008-08-21 04:21:06 +0000552 undidmsg = _("Internal error: unknown type. Please save your work");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000553 break;
554
555 }
Chris Allegrettab843a512009-04-21 05:34:08 +0000556 renumber(f);
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000557 do_gotolinecolumn(u->lineno, u->begin, FALSE, FALSE, FALSE, TRUE);
558 statusbar(_("Undid action (%s)"), undidmsg);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000559 openfile->current_undo = openfile->current_undo->next;
Chris Allegretta6f681c12008-08-08 03:02:03 +0000560 openfile->last_action = OTHER;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000561}
562
563void do_redo(void)
564{
565 undo *u = openfile->undotop;
Chris Allegrettaad37e672009-07-12 03:36:58 +0000566 filestruct *f = openfile->current;
Chris Allegretta4e12cb82008-10-14 19:55:34 +0000567 int len = 0;
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000568 char *undidmsg, *data;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000569
570 for (; u != NULL && u->next != openfile->current_undo; u = u->next)
571 ;
572 if (!u) {
573 statusbar(_("Nothing to re-do!"));
574 return;
575 }
576 if (u->next != openfile->current_undo) {
Chris Allegretta77bf1b52008-08-21 04:21:06 +0000577 statusbar(_("Internal error: Redo setup failed. Please save your work"));
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000578 return;
579 }
580
581 if (u->lineno <= f->lineno)
582 for (; f->prev != NULL && f->lineno != u->lineno; f = f->prev)
583 ;
584 else
585 for (; f->next != NULL && f->lineno != u->lineno; f = f->next)
586 ;
587 if (f->lineno != u->lineno) {
Chris Allegretta77bf1b52008-08-21 04:21:06 +0000588 statusbar(_("Internal error: can't match line %d. Please save your work"), u->lineno);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000589 return;
590 }
591#ifdef DEBUG
592 fprintf(stderr, "data we're about to redo = \"%s\"\n", f->data);
593 fprintf(stderr, "Redo running for type %d\n", u->type);
594#endif
595
596 switch(u->type) {
597 case ADD:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000598 undidmsg = _("text add");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000599 len = strlen(f->data) + strlen(u->strdata) + 1;
600 data = charalloc(len);
Chris Allegretta1f37c452008-08-01 04:11:57 +0000601 strncpy(data, f->data, u->begin);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000602 strcpy(&data[u->begin], u->strdata);
603 strcpy(&data[u->begin + strlen(u->strdata)], &f->data[u->begin]);
604 free(f->data);
605 f->data = data;
606 break;
607 case DEL:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000608 undidmsg = _("text delete");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000609 len = strlen(f->data) + strlen(u->strdata) + 1;
610 data = charalloc(len);
611 strncpy(data, f->data, u->begin);
612 strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]);
613 free(f->data);
614 f->data = data;
615 break;
Chris Allegrettab843a512009-04-21 05:34:08 +0000616 case ENTER:
617 undidmsg = _("line break");
618 do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
Chris Allegrettae061a0d2009-04-25 03:31:30 +0000619 do_enter(TRUE);
Chris Allegrettab843a512009-04-21 05:34:08 +0000620 break;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000621 case SPLIT:
Chris Allegrettab843a512009-04-21 05:34:08 +0000622 undidmsg = _("line wrap");
Chris Allegrettaa4c2b992009-04-29 22:34:27 +0000623 if (u->xflags & UNDO_SPLIT_MADENEW)
624 prepend_wrap = TRUE;
625 do_wrap(f, TRUE);
Chris Allegretta0b499d42008-07-14 07:18:22 +0000626 renumber(f);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000627 break;
628 case UNSPLIT:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000629 undidmsg = _("line join");
Chris Allegretta0b499d42008-07-14 07:18:22 +0000630 len = strlen(f->data) + strlen(u->strdata + 1);
631 data = charalloc(len);
632 strcpy(data, f->data);
633 strcat(data, u->strdata);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000634 free(f->data);
Chris Allegretta0b499d42008-07-14 07:18:22 +0000635 f->data = data;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000636 if (f->next != NULL) {
637 filestruct *tmp = f->next;
638 unlink_node(tmp);
639 delete_node(tmp);
640 }
Chris Allegretta0b499d42008-07-14 07:18:22 +0000641 renumber(f);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000642 break;
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000643 case CUT:
Chris Allegrettab549f372008-09-16 21:35:19 +0000644 undidmsg = _("text cut");
645 redo_cut(u);
646 break;
647 case UNCUT:
648 undidmsg = _("text uncut");
649 undo_cut(u);
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000650 break;
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000651 case REPLACE:
652 undidmsg = _("text replace");
653 data = u->strdata;
654 u->strdata = f->data;
655 f->data = data;
656 break;
Chris Allegrettab549f372008-09-16 21:35:19 +0000657 case INSERT:
Chris Allegrettaea577872008-08-03 20:19:42 +0000658 undidmsg = _("text insert");
Chris Allegrettaea577872008-08-03 20:19:42 +0000659 do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
Chris Allegrettab549f372008-09-16 21:35:19 +0000660 copy_from_filestruct(u->cutbuffer, u->cutbottom);
661 openfile->placewewant = xplustabs();
Chris Allegrettaea577872008-08-03 20:19:42 +0000662 break;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000663 default:
Chris Allegretta77bf1b52008-08-21 04:21:06 +0000664 undidmsg = _("Internal error: unknown type. Please save your work");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000665 break;
666
667 }
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000668 do_gotolinecolumn(u->lineno, u->begin, FALSE, FALSE, FALSE, TRUE);
669 statusbar(_("Redid action (%s)"), undidmsg);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000670
671 openfile->current_undo = u;
Chris Allegretta6f681c12008-08-08 03:02:03 +0000672 openfile->last_action = OTHER;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000673
674}
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000675#endif /* !NANO_TINY */
676
David Lawrence Ramseyb0e04c02005-12-08 07:24:54 +0000677/* Someone hits Enter *gasp!* */
Chris Allegrettae061a0d2009-04-25 03:31:30 +0000678void do_enter(bool undoing)
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000679{
680 filestruct *newnode = make_new_node(openfile->current);
681 size_t extra = 0;
682
Chris Allegrettadc7136a2008-08-21 04:24:25 +0000683 assert(openfile->current != NULL && openfile->current->data != NULL);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000684
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000685#ifndef NANO_TINY
Chris Allegrettae061a0d2009-04-25 03:31:30 +0000686 if (!undoing)
687 add_undo(ENTER);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000688
689
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000690 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
691 if (ISSET(AUTOINDENT)) {
692 /* If we are breaking the line in the indentation, the new
693 * indentation should have only current_x characters, and
694 * current_x should not change. */
695 extra = indent_length(openfile->current->data);
696 if (extra > openfile->current_x)
697 extra = openfile->current_x;
698 }
699#endif
700 newnode->data = charalloc(strlen(openfile->current->data +
701 openfile->current_x) + extra + 1);
702 strcpy(&newnode->data[extra], openfile->current->data +
703 openfile->current_x);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000704#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000705 if (ISSET(AUTOINDENT)) {
706 strncpy(newnode->data, openfile->current->data, extra);
707 openfile->totsize += mbstrlen(newnode->data);
708 }
709#endif
710 null_at(&openfile->current->data, openfile->current_x);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000711#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000712 if (openfile->mark_set && openfile->current ==
713 openfile->mark_begin && openfile->current_x <
714 openfile->mark_begin_x) {
715 openfile->mark_begin = newnode;
716 openfile->mark_begin_x += extra - openfile->current_x;
717 }
718#endif
719 openfile->current_x = extra;
720
721 if (openfile->current == openfile->filebot)
722 openfile->filebot = newnode;
723 splice_node(openfile->current, newnode,
724 openfile->current->next);
725
726 renumber(openfile->current);
727 openfile->current = newnode;
728
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000729 openfile->totsize++;
730 set_modified();
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +0000731
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000732 openfile->placewewant = xplustabs();
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +0000733
Chris Allegrettafd265af2009-02-06 03:41:02 +0000734 edit_refresh_needed = TRUE;
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000735}
736
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000737#ifndef NANO_TINY
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000738/* Send a SIGKILL (unconditional kill) to the forked process in
739 * execute_command(). */
David Lawrence Ramsey8befda62005-12-06 19:39:56 +0000740RETSIGTYPE cancel_command(int signal)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000741{
742 if (kill(pid, SIGKILL) == -1)
743 nperror("kill");
744}
745
David Lawrence Ramsey0ed71712005-11-08 23:09:47 +0000746/* Execute command in a shell. Return TRUE on success. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000747bool execute_command(const char *command)
748{
749 int fd[2];
750 FILE *f;
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000751 char *shellenv;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000752 struct sigaction oldaction, newaction;
753 /* Original and temporary handlers for SIGINT. */
754 bool sig_failed = FALSE;
755 /* Did sigaction() fail without changing the signal handlers? */
756
757 /* Make our pipes. */
758 if (pipe(fd) == -1) {
759 statusbar(_("Could not pipe"));
760 return FALSE;
761 }
762
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000763 /* Check $SHELL for the shell to use. If it isn't set, use
David Lawrence Ramsey1932dfb2005-11-29 05:52:49 +0000764 * /bin/sh. Note that $SHELL should contain only a path, with no
765 * arguments. */
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000766 shellenv = getenv("SHELL");
767 if (shellenv == NULL)
Chris Allegretta5a018f02009-11-29 06:13:22 +0000768 shellenv = (char *) "/bin/sh";
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000769
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000770 /* Fork a child. */
771 if ((pid = fork()) == 0) {
772 close(fd[0]);
773 dup2(fd[1], fileno(stdout));
774 dup2(fd[1], fileno(stderr));
775
776 /* If execl() returns at all, there was an error. */
David Lawrence Ramsey5da68ee2005-11-29 05:21:06 +0000777 execl(shellenv, tail(shellenv), "-c", command, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000778 exit(0);
779 }
780
David Lawrence Ramseyc838a4c2006-04-26 18:33:50 +0000781 /* Continue as parent. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000782 close(fd[1]);
783
784 if (pid == -1) {
785 close(fd[0]);
786 statusbar(_("Could not fork"));
787 return FALSE;
788 }
789
790 /* Before we start reading the forked command's output, we set
791 * things up so that Ctrl-C will cancel the new process. */
792
793 /* Enable interpretation of the special control keys so that we get
794 * SIGINT when Ctrl-C is pressed. */
795 enable_signals();
796
797 if (sigaction(SIGINT, NULL, &newaction) == -1) {
798 sig_failed = TRUE;
799 nperror("sigaction");
800 } else {
801 newaction.sa_handler = cancel_command;
802 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
803 sig_failed = TRUE;
804 nperror("sigaction");
805 }
806 }
807
808 /* Note that now oldaction is the previous SIGINT signal handler,
809 * to be restored later. */
810
811 f = fdopen(fd[0], "rb");
812 if (f == NULL)
813 nperror("fdopen");
814
Chris Allegrettaf8f90272009-09-03 05:45:13 +0000815 read_file(f, 0, "stdin", TRUE);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000816
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000817 if (wait(NULL) == -1)
818 nperror("wait");
819
820 if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
821 nperror("sigaction");
822
David Lawrence Ramsey8b9c91b2007-12-18 01:28:53 +0000823 /* Restore the terminal to its previous state. In the process,
824 * disable interpretation of the special control keys so that we can
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000825 * use Ctrl-C for other things. */
David Lawrence Ramsey8b9c91b2007-12-18 01:28:53 +0000826 terminal_init();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000827
828 return TRUE;
829}
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000830
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000831/* Add a new undo struct to the top of the current pile */
Chris Allegretta14c86202008-08-03 04:48:05 +0000832void add_undo(undo_type current_action)
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000833{
Chris Allegretta4e12cb82008-10-14 19:55:34 +0000834 undo *u;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000835 char *data;
Chris Allegretta14c86202008-08-03 04:48:05 +0000836 openfilestruct *fs = openfile;
Chris Allegretta5c1c1432008-10-04 11:10:11 +0000837 static undo *last_cutu = NULL; /* Last thing we cut to set up the undo for uncut */
Chris Allegretta12ba5572009-03-26 01:01:48 +0000838 ssize_t wrap_loc; /* For calculating split beginning */
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000839
Chris Allegrettaa48507d2009-08-14 03:18:29 +0000840 if (!ISSET(UNDOABLE))
Chris Allegrettaad37e672009-07-12 03:36:58 +0000841 return;
842
Chris Allegretta8f761122008-08-01 06:52:15 +0000843 /* Ugh, if we were called while cutting not-to-end, non-marked and on the same lineno,
844 we need to abort here */
845 u = fs->current_undo;
Chris Allegretta80ea9c52008-08-09 10:08:33 +0000846 if (current_action == CUT && u && u->type == CUT
847 && !u->mark_set && u->lineno == fs->current->lineno)
Chris Allegretta8f761122008-08-01 06:52:15 +0000848 return;
849
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000850 /* Blow away the old undo stack if we are starting from the middle */
Chris Allegretta91a18622008-08-01 03:50:20 +0000851 while (fs->undotop != NULL && fs->undotop != fs->current_undo) {
852 undo *u2 = fs->undotop;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000853 fs->undotop = fs->undotop->next;
Chris Allegretta91a18622008-08-01 03:50:20 +0000854 if (u2->strdata != NULL)
855 free(u2->strdata);
Chris Allegretta6f681c12008-08-08 03:02:03 +0000856 if (u2->cutbuffer)
Chris Allegrettaea577872008-08-03 20:19:42 +0000857 free_filestruct(u2->cutbuffer);
Chris Allegretta91a18622008-08-01 03:50:20 +0000858 free(u2);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000859 }
860
Chris Allegretta8f761122008-08-01 06:52:15 +0000861 /* Allocate and initialize a new undo type */
Chris Allegretta5a018f02009-11-29 06:13:22 +0000862 u = (undo *) nmalloc(sizeof(undo));
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000863 u->type = current_action;
864 u->lineno = fs->current->lineno;
865 u->begin = fs->current_x;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000866 u->next = fs->undotop;
867 fs->undotop = u;
868 fs->current_undo = u;
Chris Allegretta91a18622008-08-01 03:50:20 +0000869 u->strdata = NULL;
Chris Allegrettadf543e72009-04-12 06:13:16 +0000870 u->strdata2 = NULL;
Chris Allegretta91a18622008-08-01 03:50:20 +0000871 u->cutbuffer = NULL;
872 u->cutbottom = NULL;
Chris Allegrettab549f372008-09-16 21:35:19 +0000873 u->mark_set = 0;
Chris Allegrettad31ddb72008-08-01 07:29:06 +0000874 u->mark_begin_lineno = 0;
875 u->mark_begin_x = 0;
Chris Allegretta91a18622008-08-01 03:50:20 +0000876 u->xflags = 0;
Chris Allegrettac81cf522008-10-14 04:34:56 +0000877 u->to_end = FALSE;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000878
879 switch (u->type) {
880 /* We need to start copying data into the undo buffer or we wont be able
881 to restore it later */
882 case ADD:
883 data = charalloc(2);
884 data[0] = fs->current->data[fs->current_x];
885 data[1] = '\0';
886 u->strdata = data;
887 break;
888 case DEL:
889 if (u->begin != strlen(fs->current->data)) {
890 data = mallocstrncpy(NULL, &fs->current->data[u->begin], 2);
891 data[1] = '\0';
892 u->strdata = data;
893 break;
894 }
895 /* Else purposely fall into unsplit code */
896 current_action = u->type = UNSPLIT;
897 case UNSPLIT:
898 if (fs->current->next) {
899 data = mallocstrcpy(NULL, fs->current->next->data);
900 u->strdata = data;
901 }
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000902 break;
903 case SPLIT:
Chris Allegretta12ba5572009-03-26 01:01:48 +0000904 wrap_loc = break_line(openfile->current->data, fill
905#ifndef DISABLE_HELP
906 , FALSE
907#endif
908 );
909 u->strdata = mallocstrcpy(NULL, &openfile->current->data[wrap_loc]);
Chris Allegrettadf543e72009-04-12 06:13:16 +0000910 /* Don't both saving the next line if we're not prepending as a new line
911 will be created */
912 if (prepend_wrap)
913 u->strdata2 = mallocstrcpy(NULL, fs->current->next->data);
Chris Allegretta8b9fb362009-04-29 04:43:58 +0000914 u->begin = wrap_loc;
Chris Allegretta12ba5572009-03-26 01:01:48 +0000915 break;
916 case INSERT:
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000917 case REPLACE:
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000918 data = mallocstrcpy(NULL, fs->current->data);
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000919 u->strdata = data;
920 break;
921 case CUT:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000922 u->mark_set = openfile->mark_set;
923 if (u->mark_set) {
924 u->mark_begin_lineno = openfile->mark_begin->lineno;
925 u->mark_begin_x = openfile->mark_begin_x;
926 }
Chris Allegrettac84e7652008-10-14 01:14:12 +0000927 u->to_end = (ISSET(CUT_TO_END)) ? TRUE : FALSE;
Chris Allegretta5c1c1432008-10-04 11:10:11 +0000928 last_cutu = u;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000929 break;
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000930 case UNCUT:
Chris Allegretta5c1c1432008-10-04 11:10:11 +0000931 if (!last_cutu)
932 statusbar(_("Internal error: can't setup uncut. Please save your work."));
933 else if (last_cutu->type == CUT) {
934 u->cutbuffer = last_cutu->cutbuffer;
935 u->cutbottom = last_cutu->cutbottom;
Chris Allegretta5c1c1432008-10-04 11:10:11 +0000936 }
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000937 break;
Chris Allegrettab843a512009-04-21 05:34:08 +0000938 case ENTER:
939 break;
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000940 case OTHER:
Chris Allegretta77bf1b52008-08-21 04:21:06 +0000941 statusbar(_("Internal error: unknown type. Please save your work."));
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000942 break;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000943 }
944
945#ifdef DEBUG
Chris Allegretta6f083322009-11-11 06:00:33 +0000946 fprintf(stderr, "fs->current->data = \"%s\", current_x = %lu, u->begin = %d, type = %d\n",
947 fs->current->data, (unsigned long) fs->current_x, u->begin, current_action);
Chris Allegretta12ba5572009-03-26 01:01:48 +0000948 fprintf(stderr, "left add_undo...\n");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000949#endif
950 fs->last_action = current_action;
951}
952
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000953/* Update an undo item, or determine whether a new one
954 is really needed and bounce the data to add_undo
955 instead. The latter functionality just feels
956 gimmicky and may just be more hassle than
957 it's worth, so it should be axed if needed. */
Chris Allegretta14c86202008-08-03 04:48:05 +0000958void update_undo(undo_type action)
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000959{
960 undo *u;
961 char *data;
962 int len = 0;
Chris Allegretta14c86202008-08-03 04:48:05 +0000963 openfilestruct *fs = openfile;
Chris Allegretta91a18622008-08-01 03:50:20 +0000964
Chris Allegrettaa48507d2009-08-14 03:18:29 +0000965 if (!ISSET(UNDOABLE))
Chris Allegrettaad37e672009-07-12 03:36:58 +0000966 return;
967
Chris Allegretta91a18622008-08-01 03:50:20 +0000968#ifdef DEBUG
Chris Allegretta6f083322009-11-11 06:00:33 +0000969 fprintf(stderr, "action = %d, fs->last_action = %d, openfile->current->lineno = %lu",
970 action, fs->last_action, (unsigned long) openfile->current->lineno);
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000971 if (fs->current_undo)
Chris Allegretta6f083322009-11-11 06:00:33 +0000972 fprintf(stderr, "fs->current_undo->lineno = %lu\n", (unsigned long) fs->current_undo->lineno);
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000973 else
974 fprintf(stderr, "\n");
Chris Allegretta91a18622008-08-01 03:50:20 +0000975#endif
976
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000977 /* Change to an add if we're not using the same undo struct
978 that we should be using */
979 if (action != fs->last_action
Chris Allegrettaa4c2b992009-04-29 22:34:27 +0000980 || (action != CUT && action != INSERT && action != SPLIT
Chris Allegretta91a18622008-08-01 03:50:20 +0000981 && openfile->current->lineno != fs->current_undo->lineno)) {
Chris Allegretta14c86202008-08-03 04:48:05 +0000982 add_undo(action);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000983 return;
984 }
985
986 assert(fs->undotop != NULL);
987 u = fs->undotop;
988
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000989 switch (u->type) {
990 case ADD:
991#ifdef DEBUG
Chris Allegretta6f083322009-11-11 06:00:33 +0000992 fprintf(stderr, "fs->current->data = \"%s\", current_x = %lu, u->begin = %d\n",
993 fs->current->data, (unsigned long) fs->current_x, u->begin);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000994#endif
995 len = strlen(u->strdata) + 2;
Chris Allegretta5a018f02009-11-29 06:13:22 +0000996 data = (char *) nrealloc((void *) u->strdata, len * sizeof(char *));
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000997 data[len-2] = fs->current->data[fs->current_x];
998 data[len-1] = '\0';
999 u->strdata = (char *) data;
1000#ifdef DEBUG
1001 fprintf(stderr, "current undo data now \"%s\"\n", u->strdata);
1002#endif
1003 break;
1004 case DEL:
1005 len = strlen(u->strdata) + 2;
1006 assert(len > 2);
1007 if (fs->current_x == u->begin) {
1008 /* They're deleting */
Chris Allegretta0b499d42008-07-14 07:18:22 +00001009 if (!u->xflags)
1010 u->xflags = UNDO_DEL_DEL;
1011 else if (u->xflags != UNDO_DEL_DEL) {
Chris Allegretta14c86202008-08-03 04:48:05 +00001012 add_undo(action);
Chris Allegretta0b499d42008-07-14 07:18:22 +00001013 return;
1014 }
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001015 data = charalloc(len);
1016 strcpy(data, u->strdata);
1017 data[len-2] = fs->current->data[fs->current_x];;
1018 data[len-1] = '\0';
1019 free(u->strdata);
1020 u->strdata = data;
1021 } else if (fs->current_x == u->begin - 1) {
1022 /* They're backspacing */
Chris Allegretta0b499d42008-07-14 07:18:22 +00001023 if (!u->xflags)
1024 u->xflags = UNDO_DEL_BACKSPACE;
1025 else if (u->xflags != UNDO_DEL_BACKSPACE) {
Chris Allegretta14c86202008-08-03 04:48:05 +00001026 add_undo(action);
Chris Allegretta0b499d42008-07-14 07:18:22 +00001027 return;
1028 }
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001029 data = charalloc(len);
1030 data[0] = fs->current->data[fs->current_x];
1031 strcpy(&data[1], u->strdata);
1032 free(u->strdata);
1033 u->strdata = data;
1034 u->begin--;
1035 } else {
1036 /* They deleted something else on the line */
Chris Allegretta14c86202008-08-03 04:48:05 +00001037 add_undo(DEL);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001038 return;
1039 }
1040#ifdef DEBUG
Chris Allegretta0b499d42008-07-14 07:18:22 +00001041 fprintf(stderr, "current undo data now \"%s\"\nu->begin = %d\n", u->strdata, u->begin);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001042#endif
1043 break;
Chris Allegretta12dc8ca2008-07-31 04:24:04 +00001044 case CUT:
Chris Allegrettac84e7652008-10-14 01:14:12 +00001045 if (!cutbuffer)
1046 break;
Chris Allegretta8f761122008-08-01 06:52:15 +00001047 if (u->cutbuffer)
1048 free(u->cutbuffer);
Chris Allegretta12dc8ca2008-07-31 04:24:04 +00001049 u->cutbuffer = copy_filestruct(cutbuffer);
Chris Allegrettac81cf522008-10-14 04:34:56 +00001050 /* Compute cutbottom for the uncut using out copy */
1051 for (u->cutbottom = u->cutbuffer; u->cutbottom->next != NULL; u->cutbottom = u->cutbottom->next)
1052 ;
Chris Allegretta12dc8ca2008-07-31 04:24:04 +00001053 break;
Chris Allegretta3c1131a2008-08-02 22:31:01 +00001054 case REPLACE:
Chris Allegrettab549f372008-09-16 21:35:19 +00001055 case UNCUT:
Chris Allegretta14c86202008-08-03 04:48:05 +00001056 add_undo(action);
Chris Allegretta3c1131a2008-08-02 22:31:01 +00001057 break;
Chris Allegretta14c86202008-08-03 04:48:05 +00001058 case INSERT:
1059 u->mark_begin_lineno = openfile->current->lineno;
Chris Allegretta12ba5572009-03-26 01:01:48 +00001060 break;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001061 case SPLIT:
Chris Allegretta12ba5572009-03-26 01:01:48 +00001062 /* This will only be called if we made a completely new line,
1063 and as such we should note that so we can destroy it later */
1064 u->xflags = UNDO_SPLIT_MADENEW;
1065 break;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001066 case UNSPLIT:
Chris Allegretta3c1131a2008-08-02 22:31:01 +00001067 /* These cases are handled by the earlier check for a new line and action */
Chris Allegrettaad37e672009-07-12 03:36:58 +00001068 case ENTER:
Chris Allegretta3c1131a2008-08-02 22:31:01 +00001069 case OTHER:
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001070 break;
1071 }
1072
1073#ifdef DEBUG
1074 fprintf(stderr, "Done in udpate_undo (type was %d)\n", action);
1075#endif
1076 if (fs->last_action != action) {
1077#ifdef DEBUG
1078 fprintf(stderr, "Starting add_undo for new action as it does not match last_action\n");
1079#endif
Chris Allegretta14c86202008-08-03 04:48:05 +00001080 add_undo(action);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001081 }
1082 fs->last_action = action;
1083}
1084
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001085#endif /* !NANO_TINY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001086
1087#ifndef DISABLE_WRAPPING
David Lawrence Ramseyef0d5a72006-05-22 02:08:49 +00001088/* Unset the prepend_wrap flag. We need to do this as soon as we do
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001089 * something other than type text. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001090void wrap_reset(void)
1091{
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +00001092 prepend_wrap = FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001093}
1094
1095/* We wrap the given line. Precondition: we assume the cursor has been
David Lawrence Ramsey139fa652006-05-22 01:26:24 +00001096 * moved forward since the last typed character. Return TRUE if we
1097 * wrapped, and FALSE otherwise. */
Chris Allegrettaa4c2b992009-04-29 22:34:27 +00001098bool do_wrap(filestruct *line, bool undoing)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001099{
1100 size_t line_len;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001101 /* The length of the line we wrap. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001102 ssize_t wrap_loc;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001103 /* The index of line->data where we wrap. */
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001104#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001105 const char *indent_string = NULL;
1106 /* Indentation to prepend to the new line. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001107 size_t indent_len = 0;
1108 /* The length of indent_string. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001109#endif
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001110 const char *after_break;
1111 /* The text after the wrap point. */
1112 size_t after_break_len;
1113 /* The length of after_break. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001114 bool prepending = FALSE;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001115 /* Do we prepend to the next line? */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001116 const char *next_line = NULL;
1117 /* The next line, minus indentation. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001118 size_t next_line_len = 0;
1119 /* The length of next_line. */
1120 char *new_line = NULL;
1121 /* The line we create. */
1122 size_t new_line_len = 0;
1123 /* The eventual length of new_line. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001124
1125 /* There are three steps. First, we decide where to wrap. Then, we
1126 * create the new wrap line. Finally, we clean up. */
1127
1128 /* Step 1, finding where to wrap. We are going to add a new line
1129 * after a blank character. In this step, we call break_line() to
1130 * get the location of the last blank we can break the line at, and
David Lawrence Ramseyd4686b82006-06-11 19:14:14 +00001131 * set wrap_loc to the location of the character after it, so that
1132 * the blank is preserved at the end of the line.
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001133 *
1134 * If there is no legal wrap point, or we reach the last character
1135 * of the line while trying to find one, we should return without
1136 * wrapping. Note that if autoindent is turned on, we don't break
1137 * at the end of it! */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001138 assert(line != NULL && line->data != NULL);
1139
1140 /* Save the length of the line. */
1141 line_len = strlen(line->data);
1142
1143 /* Find the last blank where we can break the line. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001144 wrap_loc = break_line(line->data, fill
1145#ifndef DISABLE_HELP
1146 , FALSE
1147#endif
1148 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001149
1150 /* If we couldn't break the line, or we've reached the end of it, we
1151 * don't wrap. */
1152 if (wrap_loc == -1 || line->data[wrap_loc] == '\0')
1153 return FALSE;
1154
1155 /* Otherwise, move forward to the character just after the blank. */
1156 wrap_loc += move_mbright(line->data + wrap_loc, 0);
1157
1158 /* If we've reached the end of the line, we don't wrap. */
1159 if (line->data[wrap_loc] == '\0')
1160 return FALSE;
1161
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001162#ifndef NANO_TINY
Chris Allegrettaa4c2b992009-04-29 22:34:27 +00001163 if (!undoing)
1164 add_undo(SPLIT);
Chris Allegretta12ba5572009-03-26 01:01:48 +00001165
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001166 /* If autoindent is turned on, and we're on the character just after
1167 * the indentation, we don't wrap. */
1168 if (ISSET(AUTOINDENT)) {
1169 /* Get the indentation of this line. */
1170 indent_string = line->data;
1171 indent_len = indent_length(indent_string);
1172
1173 if (wrap_loc == indent_len)
1174 return FALSE;
1175 }
1176#endif
1177
1178 /* Step 2, making the new wrap line. It will consist of indentation
1179 * followed by the text after the wrap point, optionally followed by
1180 * a space (if the text after the wrap point doesn't end in a blank)
David Lawrence Ramsey03979d72006-06-11 19:15:59 +00001181 * and the text of the next line, if they can fit without wrapping,
1182 * the next line exists, and the prepend_wrap flag is set. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001183
1184 /* after_break is the text that will be wrapped to the next line. */
1185 after_break = line->data + wrap_loc;
1186 after_break_len = line_len - wrap_loc;
1187
1188 assert(strlen(after_break) == after_break_len);
1189
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +00001190 /* We prepend the wrapped text to the next line, if the prepend_wrap
1191 * flag is set, there is a next line, and prepending would not make
1192 * the line too long. */
1193 if (prepend_wrap && line != openfile->filebot) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001194 const char *end = after_break + move_mbleft(after_break,
1195 after_break_len);
1196
1197 /* If after_break doesn't end in a blank, make sure it ends in a
1198 * space. */
1199 if (!is_blank_mbchar(end)) {
1200 line_len++;
1201 line->data = charealloc(line->data, line_len + 1);
1202 line->data[line_len - 1] = ' ';
1203 line->data[line_len] = '\0';
1204 after_break = line->data + wrap_loc;
1205 after_break_len++;
1206 openfile->totsize++;
1207 }
1208
1209 next_line = line->next->data;
1210 next_line_len = strlen(next_line);
1211
1212 if (after_break_len + next_line_len <= fill) {
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001213 prepending = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001214 new_line_len += next_line_len;
1215 }
1216 }
1217
1218 /* new_line_len is now the length of the text that will be wrapped
1219 * to the next line, plus (if we're prepending to it) the length of
1220 * the text of the next line. */
1221 new_line_len += after_break_len;
1222
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001223#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001224 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001225 if (prepending) {
1226 /* If we're prepending, the indentation will come from the
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001227 * next line. */
1228 indent_string = next_line;
1229 indent_len = indent_length(indent_string);
1230 next_line += indent_len;
1231 } else {
1232 /* Otherwise, it will come from this line, in which case
1233 * we should increase new_line_len to make room for it. */
1234 new_line_len += indent_len;
1235 openfile->totsize += mbstrnlen(indent_string, indent_len);
1236 }
1237 }
1238#endif
1239
1240 /* Now we allocate the new line and copy the text into it. */
1241 new_line = charalloc(new_line_len + 1);
1242 new_line[0] = '\0';
1243
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001244#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001245 if (ISSET(AUTOINDENT)) {
1246 /* Copy the indentation. */
1247 strncpy(new_line, indent_string, indent_len);
1248 new_line[indent_len] = '\0';
1249 new_line_len += indent_len;
1250 }
1251#endif
1252
1253 /* Copy all the text after the wrap point of the current line. */
1254 strcat(new_line, after_break);
1255
1256 /* Break the current line at the wrap point. */
1257 null_at(&line->data, wrap_loc);
1258
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001259 if (prepending) {
Chris Allegrettaa4c2b992009-04-29 22:34:27 +00001260 if (!undoing)
1261 update_undo(SPLIT);
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001262 /* If we're prepending, copy the text from the next line, minus
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001263 * the indentation that we already copied above. */
1264 strcat(new_line, next_line);
1265
1266 free(line->next->data);
1267 line->next->data = new_line;
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +00001268
1269 /* If the NO_NEWLINES flag isn't set, and text has been added to
1270 * the magicline, make a new magicline. */
1271 if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0')
1272 new_magicline();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001273 } else {
1274 /* Otherwise, make a new line and copy the text after where we
1275 * broke this line to the beginning of the new line. */
1276 splice_node(openfile->current, make_new_node(openfile->current),
1277 openfile->current->next);
1278
David Lawrence Ramsey219a8142005-11-22 22:08:01 +00001279 /* If the current line is the last line of the file, move the
1280 * last line of the file down to the next line. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001281 if (openfile->filebot == openfile->current)
1282 openfile->filebot = openfile->current->next;
1283
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001284 openfile->current->next->data = new_line;
1285
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001286 openfile->totsize++;
1287 }
1288
1289 /* Step 3, clean up. Reposition the cursor and mark, and do some
1290 * other sundry things. */
1291
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +00001292 /* Set the prepend_wrap flag, so that later wraps of this line will
1293 * be prepended to the next line. */
1294 prepend_wrap = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001295
David Lawrence Ramsey2829aae2006-05-22 01:24:09 +00001296 /* Each line knows its number. We recalculate these if we inserted
1297 * a new line. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001298 if (!prepending)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001299 renumber(line);
1300
1301 /* If the cursor was after the break point, we must move it. We
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +00001302 * also clear the prepend_wrap flag in this case. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001303 if (openfile->current_x > wrap_loc) {
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +00001304 prepend_wrap = FALSE;
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001305
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001306 openfile->current = openfile->current->next;
1307 openfile->current_x -= wrap_loc
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001308#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001309 - indent_len
1310#endif
1311 ;
1312 openfile->placewewant = xplustabs();
1313 }
1314
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001315#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001316 /* If the mark was on this line after the wrap point, we move it
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001317 * down. If it was on the next line and we prepended to that line,
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001318 * we move it right. */
1319 if (openfile->mark_set) {
1320 if (openfile->mark_begin == line && openfile->mark_begin_x >
1321 wrap_loc) {
1322 openfile->mark_begin = line->next;
1323 openfile->mark_begin_x -= wrap_loc - indent_len + 1;
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +00001324 } else if (prepending && openfile->mark_begin == line->next)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001325 openfile->mark_begin_x += after_break_len;
1326 }
1327#endif
1328
1329 return TRUE;
1330}
1331#endif /* !DISABLE_WRAPPING */
1332
David Lawrence Ramseyc7c04bb2005-11-29 21:30:00 +00001333#if !defined(DISABLE_HELP) || !defined(DISABLE_WRAPJUSTIFY)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001334/* We are trying to break a chunk off line. We find the last blank such
David Lawrence Ramseycd9a5f02005-09-20 06:12:54 +00001335 * that the display length to there is at most (goal + 1). If there is
1336 * no such blank, then we find the first blank. We then take the last
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001337 * blank in that group of blanks. The terminating '\0' counts as a
1338 * blank, as does a '\n' if newline is TRUE. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001339ssize_t break_line(const char *line, ssize_t goal
1340#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001341 , bool newln
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001342#endif
1343 )
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001344{
1345 ssize_t blank_loc = -1;
1346 /* Current tentative return value. Index of the last blank we
1347 * found with short enough display width. */
1348 ssize_t cur_loc = 0;
1349 /* Current index in line. */
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +00001350 size_t cur_pos = 0;
1351 /* Current column position in line. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001352 int line_len;
1353
1354 assert(line != NULL);
1355
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +00001356 while (*line != '\0' && goal >= cur_pos) {
1357 line_len = parse_mbchar(line, NULL, &cur_pos);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001358
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001359 if (is_blank_mbchar(line)
1360#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001361 || (newln && *line == '\n')
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001362#endif
1363 ) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001364 blank_loc = cur_loc;
1365
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001366#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001367 if (newln && *line == '\n')
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001368 break;
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001369#endif
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001370 }
1371
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001372 line += line_len;
1373 cur_loc += line_len;
1374 }
1375
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +00001376 if (goal >= cur_pos)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001377 /* In fact, the whole line displays shorter than goal. */
1378 return cur_loc;
1379
Chris Allegretta09b81242008-07-12 01:54:49 +00001380#ifndef DISABLE_HELP
1381 if (newln && blank_loc <= 0) {
1382 /* If blank was not found or was found only first character,
1383 * force line break. */
1384 cur_loc -= line_len;
1385 return cur_loc;
1386 }
1387#endif
1388
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001389 if (blank_loc == -1) {
1390 /* No blank was found that was short enough. */
1391 bool found_blank = FALSE;
David Lawrence Ramsey5ab12ca2005-09-20 17:52:52 +00001392 ssize_t found_blank_loc = 0;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001393
1394 while (*line != '\0') {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001395 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001396
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001397 if (is_blank_mbchar(line)
1398#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001399 || (newln && *line == '\n')
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001400#endif
1401 ) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001402 if (!found_blank)
1403 found_blank = TRUE;
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +00001404 found_blank_loc = cur_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001405 } else if (found_blank)
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +00001406 return found_blank_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001407
1408 line += line_len;
1409 cur_loc += line_len;
1410 }
1411
1412 return -1;
1413 }
1414
1415 /* Move to the last blank after blank_loc, if there is one. */
1416 line -= cur_loc;
1417 line += blank_loc;
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001418 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001419 line += line_len;
1420
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001421 while (*line != '\0' && (is_blank_mbchar(line)
1422#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001423 || (newln && *line == '\n')
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001424#endif
1425 )) {
David Lawrence Ramseycd243f52006-05-19 23:27:16 +00001426#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001427 if (newln && *line == '\n')
David Lawrence Ramseycd243f52006-05-19 23:27:16 +00001428 break;
1429#endif
1430
David Lawrence Ramsey39bd1b32006-05-20 13:11:56 +00001431 line_len = parse_mbchar(line, NULL, NULL);
1432
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001433 line += line_len;
1434 blank_loc += line_len;
1435 }
1436
1437 return blank_loc;
1438}
David Lawrence Ramseyc7c04bb2005-11-29 21:30:00 +00001439#endif /* !DISABLE_HELP || !DISABLE_WRAPJUSTIFY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001440
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001441#if !defined(NANO_TINY) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001442/* The "indentation" of a line is the whitespace between the quote part
1443 * and the non-whitespace of the line. */
1444size_t indent_length(const char *line)
1445{
1446 size_t len = 0;
1447 char *blank_mb;
1448 int blank_mb_len;
1449
1450 assert(line != NULL);
1451
1452 blank_mb = charalloc(mb_cur_max());
1453
1454 while (*line != '\0') {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001455 blank_mb_len = parse_mbchar(line, blank_mb, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001456
1457 if (!is_blank_mbchar(blank_mb))
1458 break;
1459
1460 line += blank_mb_len;
1461 len += blank_mb_len;
1462 }
1463
1464 free(blank_mb);
1465
1466 return len;
1467}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001468#endif /* !NANO_TINY || !DISABLE_JUSTIFY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001469
1470#ifndef DISABLE_JUSTIFY
1471/* justify_format() replaces blanks with spaces and multiple spaces by 1
1472 * (except it maintains up to 2 after a character in punct optionally
1473 * followed by a character in brackets, and removes all from the end).
1474 *
1475 * justify_format() might make paragraph->data shorter, and change the
1476 * actual pointer with null_at().
1477 *
1478 * justify_format() will not look at the first skip characters of
1479 * paragraph. skip should be at most strlen(paragraph->data). The
1480 * character at paragraph[skip + 1] must not be blank. */
1481void justify_format(filestruct *paragraph, size_t skip)
1482{
1483 char *end, *new_end, *new_paragraph_data;
1484 size_t shift = 0;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001485#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001486 size_t mark_shift = 0;
1487#endif
1488
1489 /* These four asserts are assumptions about the input data. */
1490 assert(paragraph != NULL);
1491 assert(paragraph->data != NULL);
1492 assert(skip < strlen(paragraph->data));
1493 assert(!is_blank_mbchar(paragraph->data + skip));
1494
1495 end = paragraph->data + skip;
1496 new_paragraph_data = charalloc(strlen(paragraph->data) + 1);
1497 strncpy(new_paragraph_data, paragraph->data, skip);
1498 new_end = new_paragraph_data + skip;
1499
1500 while (*end != '\0') {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001501 int end_len;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001502
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001503 /* If this character is blank, change it to a space if
1504 * necessary, and skip over all blanks after it. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001505 if (is_blank_mbchar(end)) {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001506 end_len = parse_mbchar(end, NULL, NULL);
1507
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001508 *new_end = ' ';
1509 new_end++;
1510 end += end_len;
1511
1512 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001513 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001514
1515 end += end_len;
1516 shift += end_len;
1517
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001518#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001519 /* Keep track of the change in the current line. */
1520 if (openfile->mark_set && openfile->mark_begin ==
1521 paragraph && openfile->mark_begin_x >= end -
1522 paragraph->data)
1523 mark_shift += end_len;
1524#endif
1525 }
1526 /* If this character is punctuation optionally followed by a
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001527 * bracket and then followed by blanks, change no more than two
1528 * of the blanks to spaces if necessary, and skip over all
1529 * blanks after them. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001530 } else if (mbstrchr(punct, end) != NULL) {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001531 end_len = parse_mbchar(end, NULL, NULL);
1532
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001533 while (end_len > 0) {
1534 *new_end = *end;
1535 new_end++;
1536 end++;
1537 end_len--;
1538 }
1539
1540 if (*end != '\0' && mbstrchr(brackets, end) != NULL) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001541 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001542
1543 while (end_len > 0) {
1544 *new_end = *end;
1545 new_end++;
1546 end++;
1547 end_len--;
1548 }
1549 }
1550
1551 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001552 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001553
1554 *new_end = ' ';
1555 new_end++;
1556 end += end_len;
1557 }
1558
1559 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001560 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001561
1562 *new_end = ' ';
1563 new_end++;
1564 end += end_len;
1565 }
1566
1567 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001568 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001569
1570 end += end_len;
1571 shift += end_len;
1572
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001573#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001574 /* Keep track of the change in the current line. */
1575 if (openfile->mark_set && openfile->mark_begin ==
1576 paragraph && openfile->mark_begin_x >= end -
1577 paragraph->data)
1578 mark_shift += end_len;
1579#endif
1580 }
1581 /* If this character is neither blank nor punctuation, leave it
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001582 * unchanged. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001583 } else {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001584 end_len = parse_mbchar(end, NULL, NULL);
1585
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001586 while (end_len > 0) {
1587 *new_end = *end;
1588 new_end++;
1589 end++;
1590 end_len--;
1591 }
1592 }
1593 }
1594
1595 assert(*end == '\0');
1596
1597 *new_end = *end;
1598
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001599 /* If there are spaces at the end of the line, remove them. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001600 while (new_end > new_paragraph_data + skip &&
1601 *(new_end - 1) == ' ') {
1602 new_end--;
1603 shift++;
1604 }
1605
1606 if (shift > 0) {
1607 openfile->totsize -= shift;
1608 null_at(&new_paragraph_data, new_end - new_paragraph_data);
1609 free(paragraph->data);
1610 paragraph->data = new_paragraph_data;
1611
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001612#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001613 /* Adjust the mark coordinates to compensate for the change in
1614 * the current line. */
1615 if (openfile->mark_set && openfile->mark_begin == paragraph) {
1616 openfile->mark_begin_x -= mark_shift;
1617 if (openfile->mark_begin_x > new_end - new_paragraph_data)
1618 openfile->mark_begin_x = new_end - new_paragraph_data;
1619 }
1620#endif
1621 } else
1622 free(new_paragraph_data);
1623}
1624
1625/* The "quote part" of a line is the largest initial substring matching
1626 * the quote string. This function returns the length of the quote part
1627 * of the given line.
1628 *
1629 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1630 * quotestr. */
1631size_t quote_length(const char *line)
1632{
1633#ifdef HAVE_REGEX_H
1634 regmatch_t matches;
1635 int rc = regexec(&quotereg, line, 1, &matches, 0);
1636
1637 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
1638 return 0;
1639 /* matches.rm_so should be 0, since the quote string should start
1640 * with the caret ^. */
1641 return matches.rm_eo;
1642#else /* !HAVE_REGEX_H */
1643 size_t qdepth = 0;
1644
1645 /* Compute quote depth level. */
1646 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
1647 qdepth += quotelen;
1648 return qdepth;
1649#endif /* !HAVE_REGEX_H */
1650}
1651
1652/* a_line and b_line are lines of text. The quotation part of a_line is
1653 * the first a_quote characters. Check that the quotation part of
1654 * b_line is the same. */
1655bool quotes_match(const char *a_line, size_t a_quote, const char
1656 *b_line)
1657{
1658 /* Here is the assumption about a_quote. */
1659 assert(a_quote == quote_length(a_line));
1660
1661 return (a_quote == quote_length(b_line) &&
1662 strncmp(a_line, b_line, a_quote) == 0);
1663}
1664
1665/* We assume a_line and b_line have no quote part. Then, we return
1666 * whether b_line could follow a_line in a paragraph. */
1667bool indents_match(const char *a_line, size_t a_indent, const char
1668 *b_line, size_t b_indent)
1669{
1670 assert(a_indent == indent_length(a_line));
1671 assert(b_indent == indent_length(b_line));
1672
1673 return (b_indent <= a_indent &&
1674 strncmp(a_line, b_line, b_indent) == 0);
1675}
1676
1677/* Is foo the beginning of a paragraph?
1678 *
1679 * A line of text consists of a "quote part", followed by an
1680 * "indentation part", followed by text. The functions quote_length()
1681 * and indent_length() calculate these parts.
1682 *
1683 * A line is "part of a paragraph" if it has a part not in the quote
1684 * part or the indentation.
1685 *
1686 * A line is "the beginning of a paragraph" if it is part of a
1687 * paragraph and
1688 * 1) it is the top line of the file, or
1689 * 2) the line above it is not part of a paragraph, or
1690 * 3) the line above it does not have precisely the same quote
1691 * part, or
1692 * 4) the indentation of this line is not an initial substring of
1693 * the indentation of the previous line, or
1694 * 5) this line has no quote part and some indentation, and
1695 * autoindent isn't turned on.
1696 * The reason for number 5) is that if autoindent isn't turned on,
1697 * then an indented line is expected to start a paragraph, as in
1698 * books. Thus, nano can justify an indented paragraph only if
1699 * autoindent is turned on. */
1700bool begpar(const filestruct *const foo)
1701{
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +00001702 size_t quote_len, indent_len, temp_id_len;
1703
1704 if (foo == NULL)
1705 return FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001706
1707 /* Case 1). */
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +00001708 if (foo == openfile->fileage)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001709 return TRUE;
1710
1711 quote_len = quote_length(foo->data);
1712 indent_len = indent_length(foo->data + quote_len);
1713
1714 /* Not part of a paragraph. */
1715 if (foo->data[quote_len + indent_len] == '\0')
1716 return FALSE;
1717
1718 /* Case 3). */
1719 if (!quotes_match(foo->data, quote_len, foo->prev->data))
1720 return TRUE;
1721
1722 temp_id_len = indent_length(foo->prev->data + quote_len);
1723
1724 /* Case 2) or 5) or 4). */
1725 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
1726 (quote_len == 0 && indent_len > 0
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001727#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001728 && !ISSET(AUTOINDENT)
1729#endif
1730 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
1731 foo->data + quote_len, indent_len))
1732 return TRUE;
1733
1734 return FALSE;
1735}
1736
1737/* Is foo inside a paragraph? */
1738bool inpar(const filestruct *const foo)
1739{
1740 size_t quote_len;
1741
1742 if (foo == NULL)
1743 return FALSE;
1744
1745 quote_len = quote_length(foo->data);
1746
David Lawrence Ramsey21014032005-11-09 20:33:42 +00001747 return (foo->data[quote_len + indent_length(foo->data +
1748 quote_len)] != '\0');
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001749}
1750
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001751/* Move the next par_len lines, starting with first_line, into the
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001752 * justify buffer, leaving copies of those lines in place. Assume that
1753 * par_len is greater than zero, and that there are enough lines after
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001754 * first_line. */
1755void backup_lines(filestruct *first_line, size_t par_len)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001756{
1757 filestruct *top = first_line;
1758 /* The top of the paragraph we're backing up. */
1759 filestruct *bot = first_line;
1760 /* The bottom of the paragraph we're backing up. */
1761 size_t i;
1762 /* Generic loop variable. */
1763 size_t current_x_save = openfile->current_x;
1764 ssize_t fl_lineno_save = first_line->lineno;
1765 ssize_t edittop_lineno_save = openfile->edittop->lineno;
1766 ssize_t current_lineno_save = openfile->current->lineno;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001767#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001768 bool old_mark_set = openfile->mark_set;
1769 ssize_t mb_lineno_save = 0;
1770 size_t mark_begin_x_save = 0;
1771
1772 if (old_mark_set) {
1773 mb_lineno_save = openfile->mark_begin->lineno;
1774 mark_begin_x_save = openfile->mark_begin_x;
1775 }
1776#endif
1777
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001778 /* par_len will be one greater than the number of lines between
1779 * current and filebot if filebot is the last line in the
1780 * paragraph. */
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001781 assert(par_len > 0 && openfile->current->lineno + par_len <=
David Lawrence Ramsey24777c02005-12-01 05:49:08 +00001782 openfile->filebot->lineno + 1);
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001783
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001784 /* Move bot down par_len lines to the line after the last line of
1785 * the paragraph, if there is one. */
1786 for (i = par_len; i > 0 && bot != openfile->filebot; i--)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001787 bot = bot->next;
1788
1789 /* Move the paragraph from the current buffer's filestruct to the
1790 * justify buffer. */
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001791 move_to_filestruct(&jusbuffer, &jusbottom, top, 0, bot,
David Lawrence Ramseyf0575cf2005-11-09 23:27:51 +00001792 (i == 1 && bot == openfile->filebot) ? strlen(bot->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001793
1794 /* Copy the paragraph back to the current buffer's filestruct from
1795 * the justify buffer. */
1796 copy_from_filestruct(jusbuffer, jusbottom);
1797
1798 /* Move upward from the last line of the paragraph to the first
1799 * line, putting first_line, edittop, current, and mark_begin at the
1800 * same lines in the copied paragraph that they had in the original
1801 * paragraph. */
David Lawrence Ramseyee43ea62007-04-22 15:04:05 +00001802 if (openfile->current != openfile->fileage) {
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001803 top = openfile->current->prev;
David Lawrence Ramseyee43ea62007-04-22 15:04:05 +00001804#ifndef NANO_TINY
1805 if (old_mark_set &&
1806 openfile->current->lineno == mb_lineno_save) {
1807 openfile->mark_begin = openfile->current;
1808 openfile->mark_begin_x = mark_begin_x_save;
1809 }
1810#endif
1811 } else
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001812 top = openfile->current;
David Lawrence Ramseye8d505b2005-11-10 03:40:45 +00001813 for (i = par_len; i > 0 && top != NULL; i--) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001814 if (top->lineno == fl_lineno_save)
1815 first_line = top;
1816 if (top->lineno == edittop_lineno_save)
1817 openfile->edittop = top;
1818 if (top->lineno == current_lineno_save)
1819 openfile->current = top;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001820#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001821 if (old_mark_set && top->lineno == mb_lineno_save) {
1822 openfile->mark_begin = top;
1823 openfile->mark_begin_x = mark_begin_x_save;
1824 }
1825#endif
1826 top = top->prev;
1827 }
1828
1829 /* Put current_x at the same place in the copied paragraph that it
1830 * had in the original paragraph. */
1831 openfile->current_x = current_x_save;
1832
1833 set_modified();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001834}
1835
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001836/* Find the beginning of the current paragraph if we're in one, or the
1837 * beginning of the next paragraph if we're not. Afterwards, save the
1838 * quote length and paragraph length in *quote and *par. Return TRUE if
David Lawrence Ramsey139fa652006-05-22 01:26:24 +00001839 * we found a paragraph, and FALSE if there was an error or we didn't
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001840 * find a paragraph.
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001841 *
1842 * See the comment at begpar() for more about when a line is the
1843 * beginning of a paragraph. */
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001844bool find_paragraph(size_t *const quote, size_t *const par)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001845{
1846 size_t quote_len;
1847 /* Length of the initial quotation of the paragraph we search
1848 * for. */
1849 size_t par_len;
1850 /* Number of lines in the paragraph we search for. */
1851 filestruct *current_save;
1852 /* The line at the beginning of the paragraph we search for. */
1853 ssize_t current_y_save;
1854 /* The y-coordinate at the beginning of the paragraph we search
1855 * for. */
1856
1857#ifdef HAVE_REGEX_H
1858 if (quoterc != 0) {
1859 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
1860 return FALSE;
1861 }
1862#endif
1863
1864 assert(openfile->current != NULL);
1865
David Lawrence Ramsey1be131a2005-11-11 03:55:52 +00001866 /* If we're at the end of the last line of the file, it means that
1867 * there aren't any paragraphs left, so get out. */
1868 if (openfile->current == openfile->filebot && openfile->current_x ==
1869 strlen(openfile->filebot->data))
1870 return FALSE;
1871
1872 /* If the current line isn't in a paragraph, move forward to the
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001873 * last line of the next paragraph, if any. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001874 if (!inpar(openfile->current)) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001875 do_para_end(FALSE);
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001876
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001877 /* If we end up past the beginning of the line, it means that
1878 * we're at the end of the last line of the file, and the line
1879 * isn't blank, in which case the last line of the file is the
1880 * last line of the next paragraph.
1881 *
1882 * Otherwise, if we end up on a line that's in a paragraph, it
1883 * means that we're on the line after the last line of the next
1884 * paragraph, in which case we should move back to the last line
1885 * of the next paragraph. */
1886 if (openfile->current_x == 0) {
1887 if (!inpar(openfile->current->prev))
1888 return FALSE;
1889 if (openfile->current != openfile->fileage)
1890 openfile->current = openfile->current->prev;
1891 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001892 }
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001893
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001894 /* If the current line isn't the first line of the paragraph, move
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001895 * back to the first line of the paragraph. */
1896 if (!begpar(openfile->current))
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001897 do_para_begin(FALSE);
1898
1899 /* Now current is the first line of the paragraph. Set quote_len to
1900 * the quotation length of that line, and set par_len to the number
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001901 * of lines in this paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001902 quote_len = quote_length(openfile->current->data);
1903 current_save = openfile->current;
1904 current_y_save = openfile->current_y;
1905 do_para_end(FALSE);
1906 par_len = openfile->current->lineno - current_save->lineno;
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001907
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001908 /* If we end up past the beginning of the line, it means that we're
1909 * at the end of the last line of the file, and the line isn't
1910 * blank, in which case the last line of the file is part of the
1911 * paragraph. */
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00001912 if (openfile->current_x > 0)
1913 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001914 openfile->current = current_save;
1915 openfile->current_y = current_y_save;
1916
1917 /* Save the values of quote_len and par_len. */
1918 assert(quote != NULL && par != NULL);
1919
1920 *quote = quote_len;
1921 *par = par_len;
1922
1923 return TRUE;
1924}
1925
1926/* If full_justify is TRUE, justify the entire file. Otherwise, justify
1927 * the current paragraph. */
1928void do_justify(bool full_justify)
1929{
1930 filestruct *first_par_line = NULL;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001931 /* Will be the first line of the justified paragraph(s), if any.
1932 * For restoring after unjustify. */
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001933 filestruct *last_par_line = NULL;
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001934 /* Will be the line after the last line of the justified
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001935 * paragraph(s), if any. Also for restoring after unjustify. */
David Lawrence Ramsey82b5deb2005-11-10 06:07:57 +00001936 bool filebot_inpar = FALSE;
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001937 /* Whether the text at filebot is part of the current
1938 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001939
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00001940 /* We save these variables to be restored if the user
1941 * unjustifies. */
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00001942 filestruct *edittop_save = openfile->edittop;
1943 filestruct *current_save = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001944 size_t current_x_save = openfile->current_x;
1945 size_t pww_save = openfile->placewewant;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001946 size_t totsize_save = openfile->totsize;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001947#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001948 filestruct *mark_begin_save = openfile->mark_begin;
1949 size_t mark_begin_x_save = openfile->mark_begin_x;
1950#endif
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00001951 bool modified_save = openfile->modified;
1952
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001953 int kbinput;
1954 bool meta_key, func_key, s_or_t, ran_func, finished;
Chris Allegretta0018d8e2008-03-13 08:23:52 +00001955 const sc *s;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001956
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001957 /* Move to the beginning of the current line, so that justifying at
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00001958 * the end of the last line of the file, if that line isn't blank,
1959 * will work the first time through. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001960 openfile->current_x = 0;
1961
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001962 /* If we're justifying the entire file, start at the beginning. */
1963 if (full_justify)
1964 openfile->current = openfile->fileage;
1965
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001966 while (TRUE) {
1967 size_t i;
1968 /* Generic loop variable. */
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001969 filestruct *curr_first_par_line;
1970 /* The first line of the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001971 size_t quote_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001972 /* Length of the initial quotation of the current
1973 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001974 size_t indent_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001975 /* Length of the initial indentation of the current
1976 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001977 size_t par_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001978 /* Number of lines in the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001979 ssize_t break_pos;
1980 /* Where we will break lines. */
1981 char *indent_string;
1982 /* The first indentation that doesn't match the initial
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001983 * indentation of the current paragraph. This is put at the
1984 * beginning of every line broken off the first justified
1985 * line of the paragraph. Note that this works because a
1986 * paragraph can only contain two indentations at most: the
1987 * initial one, and a different one starting on a line after
1988 * the first. See the comment at begpar() for more about
1989 * when a line is part of a paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001990
1991 /* Find the first line of the paragraph to be justified. That
1992 * is the start of this paragraph if we're in one, or the start
1993 * of the next otherwise. Save the quote length and paragraph
1994 * length (number of lines). Don't refresh the screen yet,
1995 * since we'll do that after we justify.
1996 *
1997 * If the search failed, we do one of two things. If we're
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00001998 * justifying the whole file, and we've found at least one
1999 * paragraph, it means that we should justify all the way to the
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002000 * last line of the file, so set the last line of the text to be
2001 * justified to the last line of the file and break out of the
2002 * loop. Otherwise, it means that there are no paragraph(s) to
2003 * justify, so refresh the screen and get out. */
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00002004 if (!find_paragraph(&quote_len, &par_len)) {
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00002005 if (full_justify && first_par_line != NULL) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002006 last_par_line = openfile->filebot;
2007 break;
2008 } else {
Chris Allegrettafd265af2009-02-06 03:41:02 +00002009 edit_refresh_needed = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002010 return;
2011 }
2012 }
2013
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00002014 /* par_len will be one greater than the number of lines between
2015 * current and filebot if filebot is the last line in the
2016 * paragraph. Set filebot_inpar to TRUE if this is the case. */
2017 filebot_inpar = (openfile->current->lineno + par_len ==
2018 openfile->filebot->lineno + 1);
2019
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00002020 /* If we haven't already done it, move the original paragraph(s)
2021 * to the justify buffer, splice a copy of the original
2022 * paragraph(s) into the file in the same place, and set
2023 * first_par_line to the first line of the copy. */
2024 if (first_par_line == NULL) {
2025 backup_lines(openfile->current, full_justify ?
David Lawrence Ramsey53f641f2005-11-10 21:57:56 +00002026 openfile->filebot->lineno - openfile->current->lineno +
2027 ((openfile->filebot->data[0] != '\0') ? 1 : 0) :
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00002028 par_len);
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00002029 first_par_line = openfile->current;
2030 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002031
David Lawrence Ramseya6854682005-11-30 21:19:42 +00002032 /* Set curr_first_par_line to the first line of the current
2033 * paragraph. */
2034 curr_first_par_line = openfile->current;
2035
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002036 /* Initialize indent_string to a blank string. */
2037 indent_string = mallocstrcpy(NULL, "");
2038
2039 /* Find the first indentation in the paragraph that doesn't
David Lawrence Ramsey8602fd62006-05-28 18:43:21 +00002040 * match the indentation of the first line, and save it in
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002041 * indent_string. If all the indentations are the same, save
2042 * the indentation of the first line in indent_string. */
2043 {
2044 const filestruct *indent_line = openfile->current;
2045 bool past_first_line = FALSE;
2046
2047 for (i = 0; i < par_len; i++) {
2048 indent_len = quote_len +
2049 indent_length(indent_line->data + quote_len);
2050
2051 if (indent_len != strlen(indent_string)) {
2052 indent_string = mallocstrncpy(indent_string,
2053 indent_line->data, indent_len + 1);
2054 indent_string[indent_len] = '\0';
2055
2056 if (past_first_line)
2057 break;
2058 }
2059
2060 if (indent_line == openfile->current)
2061 past_first_line = TRUE;
2062
2063 indent_line = indent_line->next;
2064 }
2065 }
2066
2067 /* Now tack all the lines of the paragraph together, skipping
2068 * the quoting and indentation on all lines after the first. */
2069 for (i = 0; i < par_len - 1; i++) {
2070 filestruct *next_line = openfile->current->next;
2071 size_t line_len = strlen(openfile->current->data);
2072 size_t next_line_len =
2073 strlen(openfile->current->next->data);
2074
2075 indent_len = quote_len +
2076 indent_length(openfile->current->next->data +
2077 quote_len);
2078
2079 next_line_len -= indent_len;
2080 openfile->totsize -= indent_len;
2081
2082 /* We're just about to tack the next line onto this one. If
2083 * this line isn't empty, make sure it ends in a space. */
2084 if (line_len > 0 &&
2085 openfile->current->data[line_len - 1] != ' ') {
2086 line_len++;
2087 openfile->current->data =
2088 charealloc(openfile->current->data,
2089 line_len + 1);
2090 openfile->current->data[line_len - 1] = ' ';
2091 openfile->current->data[line_len] = '\0';
2092 openfile->totsize++;
2093 }
2094
2095 openfile->current->data =
2096 charealloc(openfile->current->data, line_len +
2097 next_line_len + 1);
2098 strcat(openfile->current->data, next_line->data +
2099 indent_len);
2100
David Lawrence Ramsey9bedc4b2005-11-09 19:51:48 +00002101 /* Don't destroy edittop or filebot! */
David Lawrence Ramsey32bd29e2005-11-09 03:44:23 +00002102 if (next_line == openfile->edittop)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002103 openfile->edittop = openfile->current;
David Lawrence Ramsey9bedc4b2005-11-09 19:51:48 +00002104 if (next_line == openfile->filebot)
2105 openfile->filebot = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002106
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002107#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002108 /* Adjust the mark coordinates to compensate for the change
2109 * in the next line. */
2110 if (openfile->mark_set && openfile->mark_begin ==
2111 next_line) {
2112 openfile->mark_begin = openfile->current;
2113 openfile->mark_begin_x += line_len - indent_len;
2114 }
2115#endif
2116
2117 unlink_node(next_line);
2118 delete_node(next_line);
2119
2120 /* If we've removed the next line, we need to go through
2121 * this line again. */
2122 i--;
2123
2124 par_len--;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002125 openfile->totsize--;
2126 }
2127
2128 /* Call justify_format() on the paragraph, which will remove
2129 * excess spaces from it and change all blank characters to
2130 * spaces. */
2131 justify_format(openfile->current, quote_len +
2132 indent_length(openfile->current->data + quote_len));
2133
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00002134 while (par_len > 0 && strlenpt(openfile->current->data) >
2135 fill) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002136 size_t line_len = strlen(openfile->current->data);
2137
2138 indent_len = strlen(indent_string);
2139
2140 /* If this line is too long, try to wrap it to the next line
2141 * to make it short enough. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00002142 break_pos = break_line(openfile->current->data + indent_len,
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00002143 fill - strnlenpt(openfile->current->data, indent_len)
2144#ifndef DISABLE_HELP
2145 , FALSE
2146#endif
2147 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002148
2149 /* We can't break the line, or don't need to, so get out. */
2150 if (break_pos == -1 || break_pos + indent_len == line_len)
2151 break;
2152
2153 /* Move forward to the character after the indentation and
2154 * just after the space. */
2155 break_pos += indent_len + 1;
2156
2157 assert(break_pos <= line_len);
2158
2159 /* Make a new line, and copy the text after where we're
2160 * going to break this line to the beginning of the new
2161 * line. */
2162 splice_node(openfile->current,
2163 make_new_node(openfile->current),
2164 openfile->current->next);
2165
2166 /* If this paragraph is non-quoted, and autoindent isn't
2167 * turned on, set the indentation length to zero so that the
2168 * indentation is treated as part of the line. */
2169 if (quote_len == 0
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002170#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002171 && !ISSET(AUTOINDENT)
2172#endif
2173 )
2174 indent_len = 0;
2175
2176 /* Copy the text after where we're going to break the
2177 * current line to the next line. */
2178 openfile->current->next->data = charalloc(indent_len + 1 +
2179 line_len - break_pos);
2180 strncpy(openfile->current->next->data, indent_string,
2181 indent_len);
2182 strcpy(openfile->current->next->data + indent_len,
2183 openfile->current->data + break_pos);
2184
2185 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002186 openfile->totsize += indent_len + 1;
2187
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002188#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002189 /* Adjust the mark coordinates to compensate for the change
2190 * in the current line. */
2191 if (openfile->mark_set && openfile->mark_begin ==
2192 openfile->current && openfile->mark_begin_x >
2193 break_pos) {
2194 openfile->mark_begin = openfile->current->next;
2195 openfile->mark_begin_x -= break_pos - indent_len;
2196 }
2197#endif
2198
2199 /* Break the current line. */
2200 null_at(&openfile->current->data, break_pos);
2201
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00002202 /* If the current line is the last line of the file, move
David Lawrence Ramseyb885c9c2005-11-10 05:20:25 +00002203 * the last line of the file down to the next line. */
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00002204 if (openfile->filebot == openfile->current)
2205 openfile->filebot = openfile->filebot->next;
2206
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002207 /* Go to the next line. */
2208 par_len--;
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00002209 openfile->current_y++;
2210 openfile->current = openfile->current->next;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002211 }
2212
2213 /* We're done breaking lines, so we don't need indent_string
2214 * anymore. */
2215 free(indent_string);
2216
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00002217 /* Go to the next line, if possible. If there is no next line,
2218 * move to the end of the current line. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00002219 if (openfile->current != openfile->filebot) {
2220 openfile->current_y++;
2221 openfile->current = openfile->current->next;
2222 } else
2223 openfile->current_x = strlen(openfile->current->data);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002224
David Lawrence Ramseya6854682005-11-30 21:19:42 +00002225 /* Renumber the lines of the now-justified current paragraph,
2226 * since both find_paragraph() and edit_refresh() need the line
2227 * numbers to be right. */
2228 renumber(curr_first_par_line);
David Lawrence Ramseyad1b64c2005-11-29 19:00:09 +00002229
2230 /* We've just finished justifying the paragraph. If we're not
2231 * justifying the entire file, break out of the loop.
2232 * Otherwise, continue the loop so that we justify all the
2233 * paragraphs in the file. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002234 if (!full_justify)
2235 break;
2236 }
2237
2238 /* We are now done justifying the paragraph or the file, so clean
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00002239 * up. current_y and totsize have been maintained above. If we
David Lawrence Ramseyad1b64c2005-11-29 19:00:09 +00002240 * actually justified something, set last_par_line to the new end of
2241 * the paragraph. */
2242 if (first_par_line != NULL)
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00002243 last_par_line = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002244
2245 edit_refresh();
2246
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00002247#ifndef NANO_TINY
David Lawrence Ramsey1c5af642006-05-10 15:15:06 +00002248 /* We're going to set jump_buf so that we return here after a
2249 * SIGWINCH instead of to main(). Indicate this. */
2250 jump_buf_main = FALSE;
2251
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00002252 /* Return here after a SIGWINCH. */
David Lawrence Ramsey1c5af642006-05-10 15:15:06 +00002253 sigsetjmp(jump_buf, 1);
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00002254#endif
2255
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002256 statusbar(_("Can now UnJustify!"));
2257
2258 /* If constant cursor position display is on, make sure the current
2259 * cursor position will be properly displayed on the statusbar. */
2260 if (ISSET(CONST_UPDATE))
2261 do_cursorpos(TRUE);
2262
2263 /* Display the shortcut list with UnJustify. */
2264 shortcut_init(TRUE);
2265 display_main_list();
2266
2267 /* Now get a keystroke and see if it's unjustify. If not, put back
2268 * the keystroke and return. */
2269 kbinput = do_input(&meta_key, &func_key, &s_or_t, &ran_func,
2270 &finished, FALSE);
Chris Allegretta0018d8e2008-03-13 08:23:52 +00002271 s = get_shortcut(currmenu, &kbinput, &meta_key, &func_key);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002272
Chris Allegrettaa1171632009-01-19 19:10:39 +00002273 if (s && s->scfunc == DO_UNCUT_TEXT) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002274 /* Splice the justify buffer back into the file, but only if we
2275 * actually justified something. */
2276 if (first_par_line != NULL) {
2277 filestruct *top_save;
2278
2279 /* Partition the filestruct so that it contains only the
2280 * text of the justified paragraph. */
2281 filepart = partition_filestruct(first_par_line, 0,
David Lawrence Ramseyccd1b7b2005-11-18 20:21:48 +00002282 last_par_line, filebot_inpar ?
2283 strlen(last_par_line->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002284
2285 /* Remove the text of the justified paragraph, and
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00002286 * replace it with the text in the justify buffer. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002287 free_filestruct(openfile->fileage);
2288 openfile->fileage = jusbuffer;
2289 openfile->filebot = jusbottom;
2290
2291 top_save = openfile->fileage;
2292
2293 /* Unpartition the filestruct so that it contains all the
2294 * text again. Note that the justified paragraph has been
2295 * replaced with the unjustified paragraph. */
2296 unpartition_filestruct(&filepart);
2297
2298 /* Renumber starting with the beginning line of the old
2299 * partition. */
2300 renumber(top_save);
2301
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00002302 /* Restore the justify we just did (ungrateful user!). */
2303 openfile->edittop = edittop_save;
2304 openfile->current = current_save;
2305 openfile->current_x = current_x_save;
2306 openfile->placewewant = pww_save;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002307 openfile->totsize = totsize_save;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002308#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002309 if (openfile->mark_set) {
2310 openfile->mark_begin = mark_begin_save;
2311 openfile->mark_begin_x = mark_begin_x_save;
2312 }
2313#endif
2314 openfile->modified = modified_save;
2315
2316 /* Clear the justify buffer. */
2317 jusbuffer = NULL;
2318
2319 if (!openfile->modified)
2320 titlebar(NULL);
Chris Allegrettafd265af2009-02-06 03:41:02 +00002321 edit_refresh_needed = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002322 }
2323 } else {
2324 unget_kbinput(kbinput, meta_key, func_key);
2325
2326 /* Blow away the text in the justify buffer. */
2327 free_filestruct(jusbuffer);
2328 jusbuffer = NULL;
2329 }
2330
2331 blank_statusbar();
2332
2333 /* Display the shortcut list with UnCut. */
2334 shortcut_init(FALSE);
2335 display_main_list();
2336}
2337
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002338/* Justify the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002339void do_justify_void(void)
2340{
2341 do_justify(FALSE);
2342}
2343
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002344/* Justify the entire file. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002345void do_full_justify(void)
2346{
2347 do_justify(TRUE);
2348}
2349#endif /* !DISABLE_JUSTIFY */
2350
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002351#ifndef DISABLE_SPELLER
2352/* A word is misspelled in the file. Let the user replace it. We
2353 * return FALSE if the user cancels. */
2354bool do_int_spell_fix(const char *word)
2355{
2356 char *save_search, *save_replace;
2357 size_t match_len, current_x_save = openfile->current_x;
2358 size_t pww_save = openfile->placewewant;
Chris Allegretta10f868d2008-03-14 04:08:51 +00002359 bool meta_key = FALSE, func_key = FALSE;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002360 filestruct *edittop_save = openfile->edittop;
2361 filestruct *current_save = openfile->current;
2362 /* Save where we are. */
2363 bool canceled = FALSE;
2364 /* The return value. */
2365 bool case_sens_set = ISSET(CASE_SENSITIVE);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002366#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002367 bool backwards_search_set = ISSET(BACKWARDS_SEARCH);
2368#endif
2369#ifdef HAVE_REGEX_H
2370 bool regexp_set = ISSET(USE_REGEXP);
2371#endif
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002372#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002373 bool old_mark_set = openfile->mark_set;
2374 bool added_magicline = FALSE;
2375 /* Whether we added a magicline after filebot. */
2376 bool right_side_up = FALSE;
2377 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
2378 * FALSE if (current, current_x) is. */
2379 filestruct *top, *bot;
2380 size_t top_x, bot_x;
2381#endif
2382
2383 /* Make sure spell-check is case sensitive. */
2384 SET(CASE_SENSITIVE);
2385
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002386#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002387 /* Make sure spell-check goes forward only. */
2388 UNSET(BACKWARDS_SEARCH);
2389#endif
2390#ifdef HAVE_REGEX_H
2391 /* Make sure spell-check doesn't use regular expressions. */
2392 UNSET(USE_REGEXP);
2393#endif
2394
2395 /* Save the current search/replace strings. */
2396 search_init_globals();
2397 save_search = last_search;
2398 save_replace = last_replace;
2399
2400 /* Set the search/replace strings to the misspelled word. */
2401 last_search = mallocstrcpy(NULL, word);
2402 last_replace = mallocstrcpy(NULL, word);
2403
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002404#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002405 if (old_mark_set) {
2406 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002407 * contains only the marked text; if the NO_NEWLINES flag isn't
2408 * set, keep track of whether the text will have a magicline
2409 * added when we're done correcting misspelled words; and
2410 * turn the mark off. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002411 mark_order((const filestruct **)&top, &top_x,
2412 (const filestruct **)&bot, &bot_x, &right_side_up);
2413 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002414 if (!ISSET(NO_NEWLINES))
2415 added_magicline = (openfile->filebot->data[0] != '\0');
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002416 openfile->mark_set = FALSE;
2417 }
2418#endif
2419
2420 /* Start from the top of the file. */
2421 openfile->edittop = openfile->fileage;
2422 openfile->current = openfile->fileage;
2423 openfile->current_x = (size_t)-1;
2424 openfile->placewewant = 0;
2425
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00002426 /* Find the first whole occurrence of word. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002427 findnextstr_wrap_reset();
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00002428 while (findnextstr(TRUE, FALSE, openfile->fileage, 0, word,
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002429 &match_len)) {
2430 if (is_whole_word(openfile->current_x, openfile->current->data,
2431 word)) {
2432 size_t xpt = xplustabs();
2433 char *exp_word = display_string(openfile->current->data,
2434 xpt, strnlenpt(openfile->current->data,
2435 openfile->current_x + match_len) - xpt, FALSE);
2436
2437 edit_refresh();
2438
2439 do_replace_highlight(TRUE, exp_word);
2440
2441 /* Allow all instances of the word to be corrected. */
David Lawrence Ramsey9d8c2842006-02-07 21:11:05 +00002442 canceled = (do_prompt(FALSE,
2443#ifndef DISABLE_TABCOMP
2444 TRUE,
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002445#endif
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002446 MSPELL, word,
Chris Allegretta10f868d2008-03-14 04:08:51 +00002447 &meta_key, &func_key,
David Lawrence Ramsey9d8c2842006-02-07 21:11:05 +00002448#ifndef NANO_TINY
2449 NULL,
2450#endif
David Lawrence Ramsey68160072006-02-18 21:32:29 +00002451 edit_refresh, _("Edit a replacement")) == -1);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002452
2453 do_replace_highlight(FALSE, exp_word);
2454
2455 free(exp_word);
2456
2457 if (!canceled && strcmp(word, answer) != 0) {
2458 openfile->current_x--;
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00002459 do_replace_loop(TRUE, &canceled, openfile->current,
2460 &openfile->current_x, word);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002461 }
2462
2463 break;
2464 }
2465 }
2466
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002467#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002468 if (old_mark_set) {
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002469 /* If the mark was on, the NO_NEWLINES flag isn't set, and we
2470 * added a magicline, remove it now. */
2471 if (!ISSET(NO_NEWLINES) && added_magicline)
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002472 remove_magicline();
2473
2474 /* Put the beginning and the end of the mark at the beginning
2475 * and the end of the spell-checked text. */
2476 if (openfile->fileage == openfile->filebot)
2477 bot_x += top_x;
2478 if (right_side_up) {
2479 openfile->mark_begin_x = top_x;
2480 current_x_save = bot_x;
2481 } else {
2482 current_x_save = top_x;
2483 openfile->mark_begin_x = bot_x;
2484 }
2485
2486 /* Unpartition the filestruct so that it contains all the text
2487 * again, and turn the mark back on. */
2488 unpartition_filestruct(&filepart);
2489 openfile->mark_set = TRUE;
2490 }
2491#endif
2492
2493 /* Restore the search/replace strings. */
2494 free(last_search);
2495 last_search = save_search;
2496 free(last_replace);
2497 last_replace = save_replace;
2498
2499 /* Restore where we were. */
2500 openfile->edittop = edittop_save;
2501 openfile->current = current_save;
2502 openfile->current_x = current_x_save;
2503 openfile->placewewant = pww_save;
2504
2505 /* Restore case sensitivity setting. */
2506 if (!case_sens_set)
2507 UNSET(CASE_SENSITIVE);
2508
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002509#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002510 /* Restore search/replace direction. */
2511 if (backwards_search_set)
2512 SET(BACKWARDS_SEARCH);
2513#endif
2514#ifdef HAVE_REGEX_H
2515 /* Restore regular expression usage setting. */
2516 if (regexp_set)
2517 SET(USE_REGEXP);
2518#endif
2519
2520 return !canceled;
2521}
2522
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002523/* Internal (integrated) spell checking using the spell program,
2524 * filtered through the sort and uniq programs. Return NULL for normal
2525 * termination, and the error string otherwise. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002526const char *do_int_speller(const char *tempfile_name)
2527{
2528 char *read_buff, *read_buff_ptr, *read_buff_word;
2529 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
2530 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
2531 pid_t pid_spell, pid_sort, pid_uniq;
2532 int spell_status, sort_status, uniq_status;
2533
2534 /* Create all three pipes up front. */
2535 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 ||
2536 pipe(uniq_fd) == -1)
2537 return _("Could not create pipe");
2538
2539 statusbar(_("Creating misspelled word list, please wait..."));
2540
2541 /* A new process to run spell in. */
2542 if ((pid_spell = fork()) == 0) {
David Lawrence Ramseyb159f942006-07-28 17:06:27 +00002543 /* Child continues (i.e. future spell process). */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002544 close(spell_fd[0]);
2545
2546 /* Replace the standard input with the temp file. */
2547 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
2548 goto close_pipes_and_exit;
2549
2550 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
2551 goto close_pipes_and_exit;
2552
2553 close(tempfile_fd);
2554
2555 /* Send spell's standard output to the pipe. */
2556 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2557 goto close_pipes_and_exit;
2558
2559 close(spell_fd[1]);
2560
David Lawrence Ramsey3239ff22005-11-29 20:01:06 +00002561 /* Start the spell program; we are using $PATH. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002562 execlp("spell", "spell", NULL);
2563
2564 /* This should not be reached if spell is found. */
2565 exit(1);
2566 }
2567
2568 /* Parent continues here. */
2569 close(spell_fd[1]);
2570
2571 /* A new process to run sort in. */
2572 if ((pid_sort = fork()) == 0) {
David Lawrence Ramseyb159f942006-07-28 17:06:27 +00002573 /* Child continues (i.e. future spell process). Replace the
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002574 * standard input with the standard output of the old pipe. */
2575 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
2576 goto close_pipes_and_exit;
2577
2578 close(spell_fd[0]);
2579
2580 /* Send sort's standard output to the new pipe. */
2581 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2582 goto close_pipes_and_exit;
2583
2584 close(sort_fd[1]);
2585
2586 /* Start the sort program. Use -f to remove mixed case. If
2587 * this isn't portable, let me know. */
2588 execlp("sort", "sort", "-f", NULL);
2589
2590 /* This should not be reached if sort is found. */
2591 exit(1);
2592 }
2593
2594 close(spell_fd[0]);
2595 close(sort_fd[1]);
2596
2597 /* A new process to run uniq in. */
2598 if ((pid_uniq = fork()) == 0) {
David Lawrence Ramseyb159f942006-07-28 17:06:27 +00002599 /* Child continues (i.e. future uniq process). Replace the
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002600 * standard input with the standard output of the old pipe. */
2601 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
2602 goto close_pipes_and_exit;
2603
2604 close(sort_fd[0]);
2605
2606 /* Send uniq's standard output to the new pipe. */
2607 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2608 goto close_pipes_and_exit;
2609
2610 close(uniq_fd[1]);
2611
2612 /* Start the uniq program; we are using PATH. */
2613 execlp("uniq", "uniq", NULL);
2614
2615 /* This should not be reached if uniq is found. */
2616 exit(1);
2617 }
2618
2619 close(sort_fd[0]);
2620 close(uniq_fd[1]);
2621
2622 /* The child process was not forked successfully. */
2623 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
2624 close(uniq_fd[0]);
2625 return _("Could not fork");
2626 }
2627
2628 /* Get the system pipe buffer size. */
2629 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
2630 close(uniq_fd[0]);
2631 return _("Could not get size of pipe buffer");
2632 }
2633
2634 /* Read in the returned spelling errors. */
2635 read_buff_read = 0;
2636 read_buff_size = pipe_buff_size + 1;
2637 read_buff = read_buff_ptr = charalloc(read_buff_size);
2638
2639 while ((bytesread = read(uniq_fd[0], read_buff_ptr,
2640 pipe_buff_size)) > 0) {
2641 read_buff_read += bytesread;
2642 read_buff_size += pipe_buff_size;
2643 read_buff = read_buff_ptr = charealloc(read_buff,
2644 read_buff_size);
2645 read_buff_ptr += read_buff_read;
2646 }
2647
2648 *read_buff_ptr = '\0';
2649 close(uniq_fd[0]);
2650
2651 /* Process the spelling errors. */
2652 read_buff_word = read_buff_ptr = read_buff;
2653
2654 while (*read_buff_ptr != '\0') {
2655 if ((*read_buff_ptr == '\r') || (*read_buff_ptr == '\n')) {
2656 *read_buff_ptr = '\0';
2657 if (read_buff_word != read_buff_ptr) {
2658 if (!do_int_spell_fix(read_buff_word)) {
2659 read_buff_word = read_buff_ptr;
2660 break;
2661 }
2662 }
2663 read_buff_word = read_buff_ptr + 1;
2664 }
2665 read_buff_ptr++;
2666 }
2667
2668 /* Special case: the last word doesn't end with '\r' or '\n'. */
2669 if (read_buff_word != read_buff_ptr)
2670 do_int_spell_fix(read_buff_word);
2671
2672 free(read_buff);
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002673 search_replace_abort();
Chris Allegrettafd265af2009-02-06 03:41:02 +00002674 edit_refresh_needed = TRUE;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002675
2676 /* Process the end of the spell process. */
2677 waitpid(pid_spell, &spell_status, 0);
2678 waitpid(pid_sort, &sort_status, 0);
2679 waitpid(pid_uniq, &uniq_status, 0);
2680
2681 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
2682 return _("Error invoking \"spell\"");
2683
2684 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
2685 return _("Error invoking \"sort -f\"");
2686
2687 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
2688 return _("Error invoking \"uniq\"");
2689
2690 /* Otherwise... */
2691 return NULL;
2692
2693 close_pipes_and_exit:
2694 /* Don't leak any handles. */
2695 close(tempfile_fd);
2696 close(spell_fd[0]);
2697 close(spell_fd[1]);
2698 close(sort_fd[0]);
2699 close(sort_fd[1]);
2700 close(uniq_fd[0]);
2701 close(uniq_fd[1]);
2702 exit(1);
2703}
2704
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002705/* External (alternate) spell checking. Return NULL for normal
2706 * termination, and the error string otherwise. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002707const char *do_alt_speller(char *tempfile_name)
2708{
2709 int alt_spell_status;
2710 size_t current_x_save = openfile->current_x;
2711 size_t pww_save = openfile->placewewant;
2712 ssize_t current_y_save = openfile->current_y;
2713 ssize_t lineno_save = openfile->current->lineno;
2714 pid_t pid_spell;
2715 char *ptr;
2716 static int arglen = 3;
2717 static char **spellargs = NULL;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002718#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002719 bool old_mark_set = openfile->mark_set;
2720 bool added_magicline = FALSE;
2721 /* Whether we added a magicline after filebot. */
2722 bool right_side_up = FALSE;
2723 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
2724 * FALSE if (current, current_x) is. */
2725 filestruct *top, *bot;
2726 size_t top_x, bot_x;
2727 ssize_t mb_lineno_save = 0;
2728 /* We're going to close the current file, and open the output of
2729 * the alternate spell command. The line that mark_begin points
2730 * to will be freed, so we save the line number and restore it
2731 * afterwards. */
2732 size_t totsize_save = openfile->totsize;
2733 /* Our saved value of totsize, used when we spell-check a marked
2734 * selection. */
2735
2736 if (old_mark_set) {
2737 /* If the mark is on, save the number of the line it starts on,
2738 * and then turn the mark off. */
2739 mb_lineno_save = openfile->mark_begin->lineno;
2740 openfile->mark_set = FALSE;
2741 }
2742#endif
2743
2744 endwin();
2745
2746 /* Set up an argument list to pass execvp(). */
2747 if (spellargs == NULL) {
2748 spellargs = (char **)nmalloc(arglen * sizeof(char *));
2749
2750 spellargs[0] = strtok(alt_speller, " ");
2751 while ((ptr = strtok(NULL, " ")) != NULL) {
2752 arglen++;
2753 spellargs = (char **)nrealloc(spellargs, arglen *
2754 sizeof(char *));
2755 spellargs[arglen - 3] = ptr;
2756 }
2757 spellargs[arglen - 1] = NULL;
2758 }
2759 spellargs[arglen - 2] = tempfile_name;
2760
2761 /* Start a new process for the alternate speller. */
2762 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey2e2112c2005-11-29 05:39:31 +00002763 /* Start alternate spell program; we are using $PATH. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002764 execvp(spellargs[0], spellargs);
2765
2766 /* Should not be reached, if alternate speller is found!!! */
2767 exit(1);
2768 }
2769
2770 /* If we couldn't fork, get out. */
2771 if (pid_spell < 0)
2772 return _("Could not fork");
2773
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002774#ifndef NANO_TINY
David Lawrence Ramseyb18482e2005-07-26 00:06:34 +00002775 /* Don't handle a pending SIGWINCH until the alternate spell checker
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002776 * is finished and we've loaded the spell-checked file back in. */
David Lawrence Ramseyb18482e2005-07-26 00:06:34 +00002777 allow_pending_sigwinch(FALSE);
2778#endif
2779
2780 /* Wait for the alternate spell checker to finish. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002781 wait(&alt_spell_status);
2782
David Lawrence Ramsey84fdb902005-08-14 20:08:49 +00002783 /* Reenter curses mode. */
2784 doupdate();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002785
2786 /* Restore the terminal to its previous state. */
2787 terminal_init();
2788
2789 /* Turn the cursor back on for sure. */
2790 curs_set(1);
2791
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002792 /* The screen might have been resized. If it has, reinitialize all
2793 * the windows based on the new screen dimensions. */
2794 window_init();
2795
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002796 if (!WIFEXITED(alt_spell_status) ||
2797 WEXITSTATUS(alt_spell_status) != 0) {
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002798 char *alt_spell_error;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002799 char *invoke_error = _("Error invoking \"%s\"");
2800
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002801#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002802 /* Turn the mark back on if it was on before. */
2803 openfile->mark_set = old_mark_set;
2804#endif
2805
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002806 alt_spell_error =
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002807 charalloc(strlen(invoke_error) +
2808 strlen(alt_speller) + 1);
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002809 sprintf(alt_spell_error, invoke_error, alt_speller);
2810 return alt_spell_error;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002811 }
2812
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002813#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002814 if (old_mark_set) {
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002815 /* If the mark is on, partition the filestruct so that it
2816 * contains only the marked text; if the NO_NEWLINES flag isn't
2817 * set, keep track of whether the text will have a magicline
2818 * added when we're done correcting misspelled words; and
2819 * turn the mark off. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002820 mark_order((const filestruct **)&top, &top_x,
2821 (const filestruct **)&bot, &bot_x, &right_side_up);
2822 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002823 if (!ISSET(NO_NEWLINES))
2824 added_magicline = (openfile->filebot->data[0] != '\0');
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002825
2826 /* Get the number of characters in the marked text, and subtract
2827 * it from the saved value of totsize. */
2828 totsize_save -= get_totsize(top, bot);
2829 }
2830#endif
2831
David Lawrence Ramsey9c984e82005-11-08 19:15:58 +00002832 /* Replace the text of the current buffer with the spell-checked
2833 * text. */
2834 replace_buffer(tempfile_name);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002835
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002836#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002837 if (old_mark_set) {
2838 filestruct *top_save = openfile->fileage;
2839
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002840 /* If the mark was on, the NO_NEWLINES flag isn't set, and we
2841 * added a magicline, remove it now. */
2842 if (!ISSET(NO_NEWLINES) && added_magicline)
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002843 remove_magicline();
2844
2845 /* Put the beginning and the end of the mark at the beginning
2846 * and the end of the spell-checked text. */
2847 if (openfile->fileage == openfile->filebot)
2848 bot_x += top_x;
2849 if (right_side_up) {
2850 openfile->mark_begin_x = top_x;
2851 current_x_save = bot_x;
2852 } else {
2853 current_x_save = top_x;
2854 openfile->mark_begin_x = bot_x;
2855 }
2856
2857 /* Unpartition the filestruct so that it contains all the text
2858 * again. Note that we've replaced the marked text originally
2859 * in the partition with the spell-checked marked text in the
2860 * temp file. */
2861 unpartition_filestruct(&filepart);
2862
2863 /* Renumber starting with the beginning line of the old
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002864 * partition. Also add the number of characters in the
2865 * spell-checked marked text to the saved value of totsize, and
2866 * then make that saved value the actual value. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002867 renumber(top_save);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002868 totsize_save += openfile->totsize;
2869 openfile->totsize = totsize_save;
2870
2871 /* Assign mark_begin to the line where the mark began before. */
2872 do_gotopos(mb_lineno_save, openfile->mark_begin_x,
2873 current_y_save, 0);
2874 openfile->mark_begin = openfile->current;
2875
2876 /* Assign mark_begin_x to the location in mark_begin where the
2877 * mark began before, adjusted for any shortening of the
2878 * line. */
2879 openfile->mark_begin_x = openfile->current_x;
2880
2881 /* Turn the mark back on. */
2882 openfile->mark_set = TRUE;
2883 }
2884#endif
2885
2886 /* Go back to the old position, and mark the file as modified. */
2887 do_gotopos(lineno_save, current_x_save, current_y_save, pww_save);
2888 set_modified();
2889
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002890#ifndef NANO_TINY
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002891 /* Handle a pending SIGWINCH again. */
2892 allow_pending_sigwinch(TRUE);
2893#endif
2894
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002895 return NULL;
2896}
2897
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002898/* Spell check the current file. If an alternate spell checker is
2899 * specified, use it. Otherwise, use the internal spell checker. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002900void do_spell(void)
2901{
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002902 bool status;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002903 FILE *temp_file;
2904 char *temp = safe_tempfile(&temp_file);
2905 const char *spell_msg;
2906
2907 if (temp == NULL) {
David Lawrence Ramseyf0e3ca62006-05-03 13:11:00 +00002908 statusbar(_("Error writing temp file: %s"), strerror(errno));
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002909 return;
2910 }
2911
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002912 status =
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002913#ifndef NANO_TINY
David Lawrence Ramsey0e1df432007-01-12 02:58:12 +00002914 openfile->mark_set ? write_marked_file(temp, temp_file, TRUE,
David Lawrence Ramseyb6c4dbf2006-11-25 22:38:17 +00002915 OVERWRITE) :
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002916#endif
David Lawrence Ramseyb6c4dbf2006-11-25 22:38:17 +00002917 write_file(temp, temp_file, TRUE, OVERWRITE, FALSE);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002918
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00002919 if (!status) {
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002920 statusbar(_("Error writing temp file: %s"), strerror(errno));
2921 free(temp);
2922 return;
2923 }
2924
2925 spell_msg = (alt_speller != NULL) ? do_alt_speller(temp) :
2926 do_int_speller(temp);
2927 unlink(temp);
2928 free(temp);
2929
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002930 currmenu = MMAIN;
David Lawrence Ramseyf32e1dd2006-06-09 17:09:51 +00002931
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002932 /* If the spell-checker printed any error messages onscreen, make
2933 * sure that they're cleared off. */
David Lawrence Ramseyf32e1dd2006-06-09 17:09:51 +00002934 total_refresh();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002935
2936 if (spell_msg != NULL) {
2937 if (errno == 0)
2938 /* Don't display an error message of "Success". */
2939 statusbar(_("Spell checking failed: %s"), spell_msg);
2940 else
2941 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
2942 strerror(errno));
2943 } else
2944 statusbar(_("Finished checking spelling"));
2945}
2946#endif /* !DISABLE_SPELLER */
2947
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002948#ifndef NANO_TINY
David Lawrence Ramseyd7f0fe92005-08-10 22:51:49 +00002949/* Our own version of "wc". Note that its character counts are in
2950 * multibyte characters instead of single-byte characters. */
David Lawrence Ramsey8e942342005-07-25 04:21:46 +00002951void do_wordlinechar_count(void)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002952{
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002953 size_t words = 0, chars = 0;
Chris Allegretta8b6461f2008-05-31 23:09:40 +00002954 ssize_t nlines = 0;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002955 size_t current_x_save = openfile->current_x;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002956 size_t pww_save = openfile->placewewant;
2957 filestruct *current_save = openfile->current;
2958 bool old_mark_set = openfile->mark_set;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002959 filestruct *top, *bot;
2960 size_t top_x, bot_x;
2961
2962 if (old_mark_set) {
2963 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +00002964 * contains only the marked text, and turn the mark off. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002965 mark_order((const filestruct **)&top, &top_x,
2966 (const filestruct **)&bot, &bot_x, NULL);
2967 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002968 openfile->mark_set = FALSE;
2969 }
2970
2971 /* Start at the top of the file. */
2972 openfile->current = openfile->fileage;
2973 openfile->current_x = 0;
2974 openfile->placewewant = 0;
2975
2976 /* Keep moving to the next word (counting punctuation characters as
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002977 * part of a word, as "wc -w" does), without updating the screen,
2978 * until we reach the end of the file, incrementing the total word
2979 * count whenever we're on a word just before moving. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002980 while (openfile->current != openfile->filebot ||
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +00002981 openfile->current->data[openfile->current_x] != '\0') {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002982 if (do_next_word(TRUE, FALSE))
2983 words++;
2984 }
2985
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002986 /* Get the total line and character counts, as "wc -l" and "wc -c"
2987 * do, but get the latter in multibyte characters. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002988 if (old_mark_set) {
Chris Allegretta8b6461f2008-05-31 23:09:40 +00002989 nlines = openfile->filebot->lineno -
David Lawrence Ramsey78a81b22005-07-25 18:59:24 +00002990 openfile->fileage->lineno + 1;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002991 chars = get_totsize(openfile->fileage, openfile->filebot);
2992
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002993 /* Unpartition the filestruct so that it contains all the text
2994 * again, and turn the mark back on. */
2995 unpartition_filestruct(&filepart);
2996 openfile->mark_set = TRUE;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002997 } else {
Chris Allegretta8b6461f2008-05-31 23:09:40 +00002998 nlines = openfile->filebot->lineno;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002999 chars = openfile->totsize;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00003000 }
3001
3002 /* Restore where we were. */
3003 openfile->current = current_save;
3004 openfile->current_x = current_x_save;
3005 openfile->placewewant = pww_save;
3006
David Lawrence Ramsey72936852005-07-25 03:47:08 +00003007 /* Display the total word, line, and character counts on the
3008 * statusbar. */
David Lawrence Ramsey7b71f572005-10-06 20:46:11 +00003009 statusbar(_("%sWords: %lu Lines: %ld Chars: %lu"), old_mark_set ?
Chris Allegretta8b6461f2008-05-31 23:09:40 +00003010 _("In Selection: ") : "", (unsigned long)words, (long)nlines,
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00003011 (unsigned long)chars);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00003012}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00003013#endif /* !NANO_TINY */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00003014
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00003015/* Get verbatim input. */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00003016void do_verbatim_input(void)
3017{
3018 int *kbinput;
3019 size_t kbinput_len, i;
3020 char *output;
3021
David Lawrence Ramseyf451d6a2006-05-27 16:02:48 +00003022 /* TRANSLATORS: This is displayed when the next keystroke will be
3023 * inserted verbatim. */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00003024 statusbar(_("Verbatim Input"));
3025
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00003026 /* Read in all the verbatim characters. */
3027 kbinput = get_verbatim_kbinput(edit, &kbinput_len);
3028
David Lawrence Ramseya620e682006-05-27 18:19:03 +00003029 /* If constant cursor position display is on, make sure the current
3030 * cursor position will be properly displayed on the statusbar.
3031 * Otherwise, blank the statusbar. */
3032 if (ISSET(CONST_UPDATE))
3033 do_cursorpos(TRUE);
3034 else {
3035 blank_statusbar();
3036 wnoutrefresh(bottomwin);
3037 }
David Lawrence Ramsey6fb66892006-05-27 17:39:19 +00003038
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00003039 /* Display all the verbatim characters at once, not filtering out
3040 * control characters. */
3041 output = charalloc(kbinput_len + 1);
3042
3043 for (i = 0; i < kbinput_len; i++)
3044 output[i] = (char)kbinput[i];
3045 output[i] = '\0';
3046
David Lawrence Ramseyad36bdc2006-12-02 17:22:21 +00003047 free(kbinput);
3048
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00003049 do_output(output, kbinput_len, TRUE);
3050
3051 free(output);
3052}
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00003053