blob: e8d986572b191c6c25fed5504822ccdab4caca01 [file] [log] [blame]
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001/* $Id$ */
2/**************************************************************************
David Lawrence Ramsey4005fc62005-10-08 06:12:41 +00003 * text.c *
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00004 * *
David Lawrence Ramsey315eb322005-11-28 19:35:29 +00005 * Copyright (C) 1999-2004 Chris Allegretta *
David Lawrence Ramsey33f2a082006-02-07 21:11:49 +00006 * Copyright (C) 2005-2006 David Lawrence Ramsey *
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 *
9 * the Free Software Foundation; either version 2, or (at your option) *
10 * 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 {
58 statusbar(_("Mark UNset"));
59 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 Ramsey6d6a36c2005-12-08 07:09:08 +000066/* Delete one character. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000067void do_delete(void)
68{
69 bool do_refresh = FALSE;
70 /* Do we have to call edit_refresh(), or can we get away with
David Lawrence Ramsey75e9dfe2006-05-18 17:50:08 +000071 * just update_line()? */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000072
73 assert(openfile->current != NULL && openfile->current->data != NULL && openfile->current_x <= strlen(openfile->current->data));
74
75 openfile->placewewant = xplustabs();
76
77 if (openfile->current->data[openfile->current_x] != '\0') {
78 int char_buf_len = parse_mbchar(openfile->current->data +
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +000079 openfile->current_x, NULL, NULL);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000080 size_t line_len = strlen(openfile->current->data +
81 openfile->current_x);
82
83 assert(openfile->current_x < strlen(openfile->current->data));
84
85 /* Let's get dangerous. */
86 charmove(&openfile->current->data[openfile->current_x],
87 &openfile->current->data[openfile->current_x +
88 char_buf_len], line_len - char_buf_len + 1);
89
90 null_at(&openfile->current->data, openfile->current_x +
91 line_len - char_buf_len);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000092#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000093 if (openfile->mark_set && openfile->mark_begin ==
94 openfile->current && openfile->current_x <
95 openfile->mark_begin_x)
96 openfile->mark_begin_x -= char_buf_len;
97#endif
98 openfile->totsize--;
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +000099 } else if (openfile->current != openfile->filebot) {
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000100 filestruct *foo = openfile->current->next;
101
102 assert(openfile->current_x == strlen(openfile->current->data));
103
104 /* If we're deleting at the end of a line, we need to call
105 * edit_refresh(). */
106 if (openfile->current->data[openfile->current_x] == '\0')
107 do_refresh = TRUE;
108
109 openfile->current->data = charealloc(openfile->current->data,
110 openfile->current_x + strlen(foo->data) + 1);
111 strcpy(openfile->current->data + openfile->current_x,
112 foo->data);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000113#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000114 if (openfile->mark_set && openfile->mark_begin ==
115 openfile->current->next) {
116 openfile->mark_begin = openfile->current;
117 openfile->mark_begin_x += openfile->current_x;
118 }
119#endif
120 if (openfile->filebot == foo)
121 openfile->filebot = openfile->current;
122
123 unlink_node(foo);
124 delete_node(foo);
125 renumber(openfile->current);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000126 openfile->totsize--;
127#ifndef DISABLE_WRAPPING
128 wrap_reset();
129#endif
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000130
David Lawrence Ramseya0168ca2005-11-05 17:35:44 +0000131 /* If the NO_NEWLINES flag isn't set, and text has been added to
132 * the magicline as a result of deleting at the end of the line
David Lawrence Ramsey0f6236f2005-11-09 00:08:29 +0000133 * before filebot, add a new magicline. */
David Lawrence Ramseya0168ca2005-11-05 17:35:44 +0000134 if (!ISSET(NO_NEWLINES) && openfile->current ==
135 openfile->filebot && openfile->current->data[0] != '\0')
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000136 new_magicline();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000137 } else
138 return;
139
David Lawrence Ramsey0f6236f2005-11-09 00:08:29 +0000140 set_modified();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000141
142#ifdef ENABLE_COLOR
143 /* If color syntaxes are available and turned on, we need to call
144 * edit_refresh(). */
145 if (openfile->colorstrings != NULL && !ISSET(NO_COLOR_SYNTAX))
146 do_refresh = TRUE;
147#endif
148
149 if (do_refresh)
150 edit_refresh();
151 else
152 update_line(openfile->current, openfile->current_x);
153}
154
David Lawrence Ramsey5b7b3e32005-12-31 21:22:54 +0000155/* Backspace over one character. That is, move the cursor left one
156 * character, and then delete the character there. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000157void do_backspace(void)
158{
159 if (openfile->current != openfile->fileage ||
160 openfile->current_x > 0) {
David Lawrence Ramsey1c3bfa92005-09-13 04:53:44 +0000161 do_left();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000162 do_delete();
163 }
164}
165
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000166/* Insert a tab. If the TABS_TO_SPACES flag is set, insert the number
167 * of spaces that a tab would normally take up. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000168void do_tab(void)
169{
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000170#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000171 if (ISSET(TABS_TO_SPACES)) {
172 char *output;
David Lawrence Ramsey90b07fc2005-10-07 15:57:48 +0000173 size_t output_len = 0, new_pww = xplustabs();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000174
175 do {
176 new_pww++;
177 output_len++;
178 } while (new_pww % tabsize != 0);
179
180 output = charalloc(output_len + 1);
181
182 charset(output, ' ', output_len);
183 output[output_len] = '\0';
184
185 do_output(output, output_len, TRUE);
186
187 free(output);
188 } else {
189#endif
190 do_output("\t", 1, TRUE);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000191#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000192 }
193#endif
194}
195
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000196#ifndef NANO_TINY
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000197/* Indent or unindent all lines covered by the mark len columns,
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000198 * depending on whether len is positive or negative. If the
199 * TABS_TO_SPACES flag is set, indent/unindent by len spaces.
200 * Otherwise, indent/unindent by (len / tabsize) tabs and (len %
201 * tabsize) spaces. */
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000202void do_indent_marked(ssize_t cols)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000203{
204 bool indent_changed = FALSE;
205 /* Whether any indenting or unindenting was done. */
206 bool unindent = FALSE;
207 /* Whether we're unindenting text. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000208 char *line_indent = NULL;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000209 /* The text added to each line in order to indent it. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000210 size_t line_indent_len = 0;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000211 /* The length of the text added to each line in order to indent
212 * it. */
213 filestruct *top, *bot, *f;
214 size_t top_x, bot_x;
215
216 assert(openfile->current != NULL && openfile->current->data != NULL);
217
218 check_statusblank();
219
220 /* If the mark isn't on, indicate it on the statusbar and get
221 * out. */
222 if (!openfile->mark_set) {
223 statusbar(_("No lines selected, nothing to do!"));
224 return;
225 }
226
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000227 /* If cols is zero, get out. */
228 if (cols == 0)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000229 return;
230
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000231 /* If cols is negative, make it positive and set unindent to
232 * TRUE. */
233 if (cols < 0) {
234 cols = -cols;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000235 unindent = TRUE;
236 /* Otherwise, we're indenting, in which case the file will always be
237 * modified, so set indent_changed to TRUE. */
238 } else
239 indent_changed = TRUE;
240
241 /* Get the coordinates of the marked text. */
242 mark_order((const filestruct **)&top, &top_x,
243 (const filestruct **)&bot, &bot_x, NULL);
244
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000245 if (!unindent) {
246 /* Set up the text we'll be using as indentation. */
247 line_indent = charalloc(cols + 1);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000248
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000249 if (ISSET(TABS_TO_SPACES)) {
250 /* Set the indentation to cols spaces. */
251 charset(line_indent, ' ', cols);
252 line_indent_len = cols;
253 } else {
254 /* Set the indentation to (cols / tabsize) tabs and (cols %
255 * tabsize) spaces. */
256 size_t num_tabs = cols / tabsize;
257 size_t num_spaces = cols % tabsize;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000258
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000259 charset(line_indent, '\t', num_tabs);
260 charset(line_indent + num_tabs, ' ', num_spaces);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000261
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000262 line_indent_len = num_tabs + num_spaces;
263 }
264
265 line_indent[line_indent_len] = '\0';
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000266 }
267
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000268 /* Go through each line of the marked text. */
269 for (f = top; f != bot->next; f = f->next) {
270 size_t line_len = strlen(f->data);
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000271 size_t indent_len = indent_length(f->data);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000272
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000273 if (!unindent) {
274 /* If we're indenting, add the characters in line_indent to
275 * the beginning of the non-whitespace text of this line. */
276 f->data = charealloc(f->data, line_len +
277 line_indent_len + 1);
278 charmove(&f->data[indent_len + line_indent_len],
279 &f->data[indent_len], line_len - indent_len + 1);
280 strncpy(f->data + indent_len, line_indent, line_indent_len);
281 openfile->totsize += line_indent_len;
282
283 /* Keep track of the change in the current line. */
284 if (f == openfile->mark_begin && openfile->mark_begin_x >=
285 indent_len)
286 openfile->mark_begin_x += line_indent_len;
287
288 if (f == openfile->current && openfile->current_x >=
289 indent_len)
290 openfile->current_x += line_indent_len;
291
292 /* If the NO_NEWLINES flag isn't set, and this is the
293 * magicline, add a new magicline. */
294 if (!ISSET(NO_NEWLINES) && f == openfile->filebot)
295 new_magicline();
296 } else {
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000297 size_t indent_col = strnlenpt(f->data, indent_len);
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000298 /* The length in columns of the indentation on this
299 * line. */
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000300
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000301 if (cols <= indent_col) {
302 size_t indent_new = actual_x(f->data, indent_col -
303 cols);
David Lawrence Ramsey5bb77272006-05-06 14:37:33 +0000304 /* The length of the indentation remaining on
305 * this line after we unindent. */
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000306 size_t indent_shift = indent_len - indent_new;
David Lawrence Ramsey5bb77272006-05-06 14:37:33 +0000307 /* The change in the indentation on this line
308 * after we unindent. */
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000309
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000310 /* If we're unindenting, and there's at least cols
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000311 * columns' worth of indentation at the beginning of the
312 * non-whitespace text of this line, remove it. */
313 charmove(&f->data[indent_new], &f->data[indent_len],
314 line_len - indent_shift - indent_new + 1);
315 null_at(&f->data, line_len - indent_shift + 1);
316 openfile->totsize -= indent_shift;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000317
David Lawrence Ramsey2e8fac62006-04-29 15:44:58 +0000318 /* Keep track of the change in the current line. */
David Lawrence Ramsey2e8fac62006-04-29 15:44:58 +0000319 if (f == openfile->mark_begin &&
David Lawrence Ramseyeb4f90e2006-05-05 14:22:42 +0000320 openfile->mark_begin_x > indent_new) {
321 if (openfile->mark_begin_x <= indent_len)
322 openfile->mark_begin_x = indent_new;
323 else
324 openfile->mark_begin_x -= indent_shift;
325 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000326
David Lawrence Ramseyac37b042006-05-03 12:59:05 +0000327 if (f == openfile->current && openfile->current_x >
David Lawrence Ramseyeb4f90e2006-05-05 14:22:42 +0000328 indent_new) {
329 if (openfile->current_x <= indent_len)
330 openfile->current_x = indent_new;
331 else
332 openfile->current_x -= indent_shift;
333 }
David Lawrence Ramsey7194a612006-04-29 16:11:21 +0000334
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000335 /* We've unindented, so set indent_changed to TRUE. */
336 if (!indent_changed)
337 indent_changed = TRUE;
338 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000339 }
340 }
341
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000342 if (!unindent)
David Lawrence Ramsey25456862006-05-05 15:43:52 +0000343 /* Clean up. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000344 free(line_indent);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000345
346 if (indent_changed) {
347 /* Mark the file as modified. */
348 set_modified();
349
350 /* Update the screen. */
351 edit_refresh();
352 }
353}
354
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000355/* Indent all lines covered by the mark tabsize columns. */
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000356void do_indent_marked_void(void)
357{
358 do_indent_marked(tabsize);
359}
360
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000361/* Unindent all lines covered by the mark tabsize columns. */
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000362void do_unindent_marked_void(void)
363{
364 do_indent_marked(-tabsize);
365}
366#endif /* !NANO_TINY */
367
David Lawrence Ramseyb0e04c02005-12-08 07:24:54 +0000368/* Someone hits Enter *gasp!* */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000369void do_enter(void)
370{
371 filestruct *newnode = make_new_node(openfile->current);
372 size_t extra = 0;
373
374 assert(openfile->current != NULL && openfile->current->data != NULL);
375
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000376#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000377 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
378 if (ISSET(AUTOINDENT)) {
379 /* If we are breaking the line in the indentation, the new
380 * indentation should have only current_x characters, and
381 * current_x should not change. */
382 extra = indent_length(openfile->current->data);
383 if (extra > openfile->current_x)
384 extra = openfile->current_x;
385 }
386#endif
387 newnode->data = charalloc(strlen(openfile->current->data +
388 openfile->current_x) + extra + 1);
389 strcpy(&newnode->data[extra], openfile->current->data +
390 openfile->current_x);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000391#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000392 if (ISSET(AUTOINDENT)) {
393 strncpy(newnode->data, openfile->current->data, extra);
394 openfile->totsize += mbstrlen(newnode->data);
395 }
396#endif
397 null_at(&openfile->current->data, openfile->current_x);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000398#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000399 if (openfile->mark_set && openfile->current ==
400 openfile->mark_begin && openfile->current_x <
401 openfile->mark_begin_x) {
402 openfile->mark_begin = newnode;
403 openfile->mark_begin_x += extra - openfile->current_x;
404 }
405#endif
406 openfile->current_x = extra;
407
408 if (openfile->current == openfile->filebot)
409 openfile->filebot = newnode;
410 splice_node(openfile->current, newnode,
411 openfile->current->next);
412
413 renumber(openfile->current);
414 openfile->current = newnode;
415
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000416 openfile->totsize++;
417 set_modified();
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +0000418
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000419 openfile->placewewant = xplustabs();
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +0000420
421 edit_refresh();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000422}
423
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000424#ifndef NANO_TINY
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000425/* Send a SIGKILL (unconditional kill) to the forked process in
426 * execute_command(). */
David Lawrence Ramsey8befda62005-12-06 19:39:56 +0000427RETSIGTYPE cancel_command(int signal)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000428{
429 if (kill(pid, SIGKILL) == -1)
430 nperror("kill");
431}
432
David Lawrence Ramsey0ed71712005-11-08 23:09:47 +0000433/* Execute command in a shell. Return TRUE on success. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000434bool execute_command(const char *command)
435{
436 int fd[2];
437 FILE *f;
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000438 char *shellenv;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000439 struct sigaction oldaction, newaction;
440 /* Original and temporary handlers for SIGINT. */
441 bool sig_failed = FALSE;
442 /* Did sigaction() fail without changing the signal handlers? */
443
444 /* Make our pipes. */
445 if (pipe(fd) == -1) {
446 statusbar(_("Could not pipe"));
447 return FALSE;
448 }
449
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000450 /* Check $SHELL for the shell to use. If it isn't set, use
David Lawrence Ramsey1932dfb2005-11-29 05:52:49 +0000451 * /bin/sh. Note that $SHELL should contain only a path, with no
452 * arguments. */
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000453 shellenv = getenv("SHELL");
454 if (shellenv == NULL)
455 shellenv = "/bin/sh";
456
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000457 /* Fork a child. */
458 if ((pid = fork()) == 0) {
459 close(fd[0]);
460 dup2(fd[1], fileno(stdout));
461 dup2(fd[1], fileno(stderr));
462
463 /* If execl() returns at all, there was an error. */
David Lawrence Ramsey5da68ee2005-11-29 05:21:06 +0000464 execl(shellenv, tail(shellenv), "-c", command, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000465 exit(0);
466 }
467
David Lawrence Ramseyc838a4c2006-04-26 18:33:50 +0000468 /* Continue as parent. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000469 close(fd[1]);
470
471 if (pid == -1) {
472 close(fd[0]);
473 statusbar(_("Could not fork"));
474 return FALSE;
475 }
476
477 /* Before we start reading the forked command's output, we set
478 * things up so that Ctrl-C will cancel the new process. */
479
480 /* Enable interpretation of the special control keys so that we get
481 * SIGINT when Ctrl-C is pressed. */
482 enable_signals();
483
484 if (sigaction(SIGINT, NULL, &newaction) == -1) {
485 sig_failed = TRUE;
486 nperror("sigaction");
487 } else {
488 newaction.sa_handler = cancel_command;
489 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
490 sig_failed = TRUE;
491 nperror("sigaction");
492 }
493 }
494
495 /* Note that now oldaction is the previous SIGINT signal handler,
496 * to be restored later. */
497
498 f = fdopen(fd[0], "rb");
499 if (f == NULL)
500 nperror("fdopen");
501
502 read_file(f, "stdin");
503
504 /* If multibuffer mode is on, we could be here in view mode. If so,
505 * don't set the modification flag. */
506 if (!ISSET(VIEW_MODE))
507 set_modified();
508
509 if (wait(NULL) == -1)
510 nperror("wait");
511
512 if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
513 nperror("sigaction");
514
515 /* Disable interpretation of the special control keys so that we can
516 * use Ctrl-C for other things. */
517 disable_signals();
518
519 return TRUE;
520}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000521#endif /* !NANO_TINY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000522
523#ifndef DISABLE_WRAPPING
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000524/* Clear the prepend_wrap flag. We need to do this as soon as we do
525 * something other than type text. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000526void wrap_reset(void)
527{
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000528 prepend_wrap = FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000529}
530
531/* We wrap the given line. Precondition: we assume the cursor has been
532 * moved forward since the last typed character. Return value: whether
533 * we wrapped. */
534bool do_wrap(filestruct *line)
535{
536 size_t line_len;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000537 /* The length of the line we wrap. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000538 ssize_t wrap_loc;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000539 /* The index of line->data where we wrap. */
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000540#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000541 const char *indent_string = NULL;
542 /* Indentation to prepend to the new line. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000543 size_t indent_len = 0;
544 /* The length of indent_string. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000545#endif
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000546 const char *after_break;
547 /* The text after the wrap point. */
548 size_t after_break_len;
549 /* The length of after_break. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000550 bool prepending = FALSE;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000551 /* Do we prepend to the next line? */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000552 const char *next_line = NULL;
553 /* The next line, minus indentation. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000554 size_t next_line_len = 0;
555 /* The length of next_line. */
556 char *new_line = NULL;
557 /* The line we create. */
558 size_t new_line_len = 0;
559 /* The eventual length of new_line. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000560
561 /* There are three steps. First, we decide where to wrap. Then, we
562 * create the new wrap line. Finally, we clean up. */
563
564 /* Step 1, finding where to wrap. We are going to add a new line
565 * after a blank character. In this step, we call break_line() to
566 * get the location of the last blank we can break the line at, and
567 * and set wrap_loc to the location of the character after it, so
568 * that the blank is preserved at the end of the line.
569 *
570 * If there is no legal wrap point, or we reach the last character
571 * of the line while trying to find one, we should return without
572 * wrapping. Note that if autoindent is turned on, we don't break
573 * at the end of it! */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000574 assert(line != NULL && line->data != NULL);
575
576 /* Save the length of the line. */
577 line_len = strlen(line->data);
578
579 /* Find the last blank where we can break the line. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000580 wrap_loc = break_line(line->data, fill
581#ifndef DISABLE_HELP
582 , FALSE
583#endif
584 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000585
586 /* If we couldn't break the line, or we've reached the end of it, we
587 * don't wrap. */
588 if (wrap_loc == -1 || line->data[wrap_loc] == '\0')
589 return FALSE;
590
591 /* Otherwise, move forward to the character just after the blank. */
592 wrap_loc += move_mbright(line->data + wrap_loc, 0);
593
594 /* If we've reached the end of the line, we don't wrap. */
595 if (line->data[wrap_loc] == '\0')
596 return FALSE;
597
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000598#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000599 /* If autoindent is turned on, and we're on the character just after
600 * the indentation, we don't wrap. */
601 if (ISSET(AUTOINDENT)) {
602 /* Get the indentation of this line. */
603 indent_string = line->data;
604 indent_len = indent_length(indent_string);
605
606 if (wrap_loc == indent_len)
607 return FALSE;
608 }
609#endif
610
611 /* Step 2, making the new wrap line. It will consist of indentation
612 * followed by the text after the wrap point, optionally followed by
613 * a space (if the text after the wrap point doesn't end in a blank)
614 * and the text of the next line, if they can fit without
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000615 * wrapping, the next line exists, and the prepend_wrap flag is
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000616 * set. */
617
618 /* after_break is the text that will be wrapped to the next line. */
619 after_break = line->data + wrap_loc;
620 after_break_len = line_len - wrap_loc;
621
622 assert(strlen(after_break) == after_break_len);
623
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000624 /* We prepend the wrapped text to the next line, if the prepend_wrap
625 * flag is set, there is a next line, and prepending would not make
626 * the line too long. */
627 if (prepend_wrap && line != openfile->filebot) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000628 const char *end = after_break + move_mbleft(after_break,
629 after_break_len);
630
631 /* If after_break doesn't end in a blank, make sure it ends in a
632 * space. */
633 if (!is_blank_mbchar(end)) {
634 line_len++;
635 line->data = charealloc(line->data, line_len + 1);
636 line->data[line_len - 1] = ' ';
637 line->data[line_len] = '\0';
638 after_break = line->data + wrap_loc;
639 after_break_len++;
640 openfile->totsize++;
641 }
642
643 next_line = line->next->data;
644 next_line_len = strlen(next_line);
645
646 if (after_break_len + next_line_len <= fill) {
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000647 prepending = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000648 new_line_len += next_line_len;
649 }
650 }
651
652 /* new_line_len is now the length of the text that will be wrapped
653 * to the next line, plus (if we're prepending to it) the length of
654 * the text of the next line. */
655 new_line_len += after_break_len;
656
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000657#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000658 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000659 if (prepending) {
660 /* If we're prepending, the indentation will come from the
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000661 * next line. */
662 indent_string = next_line;
663 indent_len = indent_length(indent_string);
664 next_line += indent_len;
665 } else {
666 /* Otherwise, it will come from this line, in which case
667 * we should increase new_line_len to make room for it. */
668 new_line_len += indent_len;
669 openfile->totsize += mbstrnlen(indent_string, indent_len);
670 }
671 }
672#endif
673
674 /* Now we allocate the new line and copy the text into it. */
675 new_line = charalloc(new_line_len + 1);
676 new_line[0] = '\0';
677
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000678#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000679 if (ISSET(AUTOINDENT)) {
680 /* Copy the indentation. */
681 strncpy(new_line, indent_string, indent_len);
682 new_line[indent_len] = '\0';
683 new_line_len += indent_len;
684 }
685#endif
686
687 /* Copy all the text after the wrap point of the current line. */
688 strcat(new_line, after_break);
689
690 /* Break the current line at the wrap point. */
691 null_at(&line->data, wrap_loc);
692
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000693 if (prepending) {
694 /* If we're prepending, copy the text from the next line, minus
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000695 * the indentation that we already copied above. */
696 strcat(new_line, next_line);
697
698 free(line->next->data);
699 line->next->data = new_line;
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000700
701 /* If the NO_NEWLINES flag isn't set, and text has been added to
702 * the magicline, make a new magicline. */
703 if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0')
704 new_magicline();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000705 } else {
706 /* Otherwise, make a new line and copy the text after where we
707 * broke this line to the beginning of the new line. */
708 splice_node(openfile->current, make_new_node(openfile->current),
709 openfile->current->next);
710
David Lawrence Ramsey219a8142005-11-22 22:08:01 +0000711 /* If the current line is the last line of the file, move the
712 * last line of the file down to the next line. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000713 if (openfile->filebot == openfile->current)
714 openfile->filebot = openfile->current->next;
715
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000716 openfile->current->next->data = new_line;
717
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000718 openfile->totsize++;
719 }
720
721 /* Step 3, clean up. Reposition the cursor and mark, and do some
722 * other sundry things. */
723
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000724 /* Set the prepend_wrap flag, so that later wraps of this line will
725 * be prepended to the next line. */
726 prepend_wrap = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000727
728 /* Each line knows its line number. We recalculate these if we
729 * inserted a new line. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000730 if (!prepending)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000731 renumber(line);
732
733 /* If the cursor was after the break point, we must move it. We
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000734 * also clear the prepend_wrap flag in this case. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000735 if (openfile->current_x > wrap_loc) {
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000736 prepend_wrap = FALSE;
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000737
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000738 openfile->current = openfile->current->next;
739 openfile->current_x -= wrap_loc
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000740#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000741 - indent_len
742#endif
743 ;
744 openfile->placewewant = xplustabs();
745 }
746
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000747#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000748 /* If the mark was on this line after the wrap point, we move it
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000749 * down. If it was on the next line and we prepended to that line,
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000750 * we move it right. */
751 if (openfile->mark_set) {
752 if (openfile->mark_begin == line && openfile->mark_begin_x >
753 wrap_loc) {
754 openfile->mark_begin = line->next;
755 openfile->mark_begin_x -= wrap_loc - indent_len + 1;
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000756 } else if (prepending && openfile->mark_begin == line->next)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000757 openfile->mark_begin_x += after_break_len;
758 }
759#endif
760
761 return TRUE;
762}
763#endif /* !DISABLE_WRAPPING */
764
David Lawrence Ramseyc7c04bb2005-11-29 21:30:00 +0000765#if !defined(DISABLE_HELP) || !defined(DISABLE_WRAPJUSTIFY)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000766/* We are trying to break a chunk off line. We find the last blank such
David Lawrence Ramseycd9a5f02005-09-20 06:12:54 +0000767 * that the display length to there is at most (goal + 1). If there is
768 * no such blank, then we find the first blank. We then take the last
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000769 * blank in that group of blanks. The terminating '\0' counts as a
770 * blank, as does a '\n' if newline is TRUE. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000771ssize_t break_line(const char *line, ssize_t goal
772#ifndef DISABLE_HELP
773 , bool newline
774#endif
775 )
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000776{
777 ssize_t blank_loc = -1;
778 /* Current tentative return value. Index of the last blank we
779 * found with short enough display width. */
780 ssize_t cur_loc = 0;
781 /* Current index in line. */
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +0000782 size_t cur_pos = 0;
783 /* Current column position in line. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000784 int line_len;
785
786 assert(line != NULL);
787
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +0000788 while (*line != '\0' && goal >= cur_pos) {
789 line_len = parse_mbchar(line, NULL, &cur_pos);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000790
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000791 if (is_blank_mbchar(line)
792#ifndef DISABLE_HELP
793 || (newline && *line == '\n')
794#endif
795 ) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000796 blank_loc = cur_loc;
797
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000798#ifndef DISABLE_HELP
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000799 if (newline && *line == '\n')
800 break;
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000801#endif
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000802 }
803
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000804 line += line_len;
805 cur_loc += line_len;
806 }
807
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +0000808 if (goal >= cur_pos)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000809 /* In fact, the whole line displays shorter than goal. */
810 return cur_loc;
811
812 if (blank_loc == -1) {
813 /* No blank was found that was short enough. */
814 bool found_blank = FALSE;
David Lawrence Ramsey5ab12ca2005-09-20 17:52:52 +0000815 ssize_t found_blank_loc = 0;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000816
817 while (*line != '\0') {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000818 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000819
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000820 if (is_blank_mbchar(line)
821#ifndef DISABLE_HELP
822 || (newline && *line == '\n')
823#endif
824 ) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000825 if (!found_blank)
826 found_blank = TRUE;
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +0000827 found_blank_loc = cur_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000828 } else if (found_blank)
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +0000829 return found_blank_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000830
831 line += line_len;
832 cur_loc += line_len;
833 }
834
835 return -1;
836 }
837
838 /* Move to the last blank after blank_loc, if there is one. */
839 line -= cur_loc;
840 line += blank_loc;
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000841 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000842 line += line_len;
843
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000844 while (*line != '\0' && (is_blank_mbchar(line)
845#ifndef DISABLE_HELP
846 || (newline && *line == '\n')
847#endif
848 )) {
David Lawrence Ramseycd243f52006-05-19 23:27:16 +0000849#ifndef DISABLE_HELP
850 if (newline && *line == '\n')
851 break;
852#endif
853
David Lawrence Ramsey39bd1b32006-05-20 13:11:56 +0000854 line_len = parse_mbchar(line, NULL, NULL);
855
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000856 line += line_len;
857 blank_loc += line_len;
858 }
859
860 return blank_loc;
861}
David Lawrence Ramseyc7c04bb2005-11-29 21:30:00 +0000862#endif /* !DISABLE_HELP || !DISABLE_WRAPJUSTIFY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000863
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000864#if !defined(NANO_TINY) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000865/* The "indentation" of a line is the whitespace between the quote part
866 * and the non-whitespace of the line. */
867size_t indent_length(const char *line)
868{
869 size_t len = 0;
870 char *blank_mb;
871 int blank_mb_len;
872
873 assert(line != NULL);
874
875 blank_mb = charalloc(mb_cur_max());
876
877 while (*line != '\0') {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000878 blank_mb_len = parse_mbchar(line, blank_mb, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000879
880 if (!is_blank_mbchar(blank_mb))
881 break;
882
883 line += blank_mb_len;
884 len += blank_mb_len;
885 }
886
887 free(blank_mb);
888
889 return len;
890}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000891#endif /* !NANO_TINY || !DISABLE_JUSTIFY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000892
893#ifndef DISABLE_JUSTIFY
894/* justify_format() replaces blanks with spaces and multiple spaces by 1
895 * (except it maintains up to 2 after a character in punct optionally
896 * followed by a character in brackets, and removes all from the end).
897 *
898 * justify_format() might make paragraph->data shorter, and change the
899 * actual pointer with null_at().
900 *
901 * justify_format() will not look at the first skip characters of
902 * paragraph. skip should be at most strlen(paragraph->data). The
903 * character at paragraph[skip + 1] must not be blank. */
904void justify_format(filestruct *paragraph, size_t skip)
905{
906 char *end, *new_end, *new_paragraph_data;
907 size_t shift = 0;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000908#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000909 size_t mark_shift = 0;
910#endif
911
912 /* These four asserts are assumptions about the input data. */
913 assert(paragraph != NULL);
914 assert(paragraph->data != NULL);
915 assert(skip < strlen(paragraph->data));
916 assert(!is_blank_mbchar(paragraph->data + skip));
917
918 end = paragraph->data + skip;
919 new_paragraph_data = charalloc(strlen(paragraph->data) + 1);
920 strncpy(new_paragraph_data, paragraph->data, skip);
921 new_end = new_paragraph_data + skip;
922
923 while (*end != '\0') {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000924 int end_len;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000925
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000926 /* If this character is blank, change it to a space if
927 * necessary, and skip over all blanks after it. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000928 if (is_blank_mbchar(end)) {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000929 end_len = parse_mbchar(end, NULL, NULL);
930
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000931 *new_end = ' ';
932 new_end++;
933 end += end_len;
934
935 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000936 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000937
938 end += end_len;
939 shift += end_len;
940
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000941#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000942 /* Keep track of the change in the current line. */
943 if (openfile->mark_set && openfile->mark_begin ==
944 paragraph && openfile->mark_begin_x >= end -
945 paragraph->data)
946 mark_shift += end_len;
947#endif
948 }
949 /* If this character is punctuation optionally followed by a
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000950 * bracket and then followed by blanks, change no more than two
951 * of the blanks to spaces if necessary, and skip over all
952 * blanks after them. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000953 } else if (mbstrchr(punct, end) != NULL) {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000954 end_len = parse_mbchar(end, NULL, NULL);
955
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000956 while (end_len > 0) {
957 *new_end = *end;
958 new_end++;
959 end++;
960 end_len--;
961 }
962
963 if (*end != '\0' && mbstrchr(brackets, end) != NULL) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000964 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000965
966 while (end_len > 0) {
967 *new_end = *end;
968 new_end++;
969 end++;
970 end_len--;
971 }
972 }
973
974 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000975 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000976
977 *new_end = ' ';
978 new_end++;
979 end += end_len;
980 }
981
982 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000983 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000984
985 *new_end = ' ';
986 new_end++;
987 end += end_len;
988 }
989
990 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000991 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000992
993 end += end_len;
994 shift += end_len;
995
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000996#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000997 /* Keep track of the change in the current line. */
998 if (openfile->mark_set && openfile->mark_begin ==
999 paragraph && openfile->mark_begin_x >= end -
1000 paragraph->data)
1001 mark_shift += end_len;
1002#endif
1003 }
1004 /* If this character is neither blank nor punctuation, leave it
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001005 * unchanged. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001006 } else {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001007 end_len = parse_mbchar(end, NULL, NULL);
1008
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001009 while (end_len > 0) {
1010 *new_end = *end;
1011 new_end++;
1012 end++;
1013 end_len--;
1014 }
1015 }
1016 }
1017
1018 assert(*end == '\0');
1019
1020 *new_end = *end;
1021
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001022 /* If there are spaces at the end of the line, remove them. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001023 while (new_end > new_paragraph_data + skip &&
1024 *(new_end - 1) == ' ') {
1025 new_end--;
1026 shift++;
1027 }
1028
1029 if (shift > 0) {
1030 openfile->totsize -= shift;
1031 null_at(&new_paragraph_data, new_end - new_paragraph_data);
1032 free(paragraph->data);
1033 paragraph->data = new_paragraph_data;
1034
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001035#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001036 /* Adjust the mark coordinates to compensate for the change in
1037 * the current line. */
1038 if (openfile->mark_set && openfile->mark_begin == paragraph) {
1039 openfile->mark_begin_x -= mark_shift;
1040 if (openfile->mark_begin_x > new_end - new_paragraph_data)
1041 openfile->mark_begin_x = new_end - new_paragraph_data;
1042 }
1043#endif
1044 } else
1045 free(new_paragraph_data);
1046}
1047
1048/* The "quote part" of a line is the largest initial substring matching
1049 * the quote string. This function returns the length of the quote part
1050 * of the given line.
1051 *
1052 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1053 * quotestr. */
1054size_t quote_length(const char *line)
1055{
1056#ifdef HAVE_REGEX_H
1057 regmatch_t matches;
1058 int rc = regexec(&quotereg, line, 1, &matches, 0);
1059
1060 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
1061 return 0;
1062 /* matches.rm_so should be 0, since the quote string should start
1063 * with the caret ^. */
1064 return matches.rm_eo;
1065#else /* !HAVE_REGEX_H */
1066 size_t qdepth = 0;
1067
1068 /* Compute quote depth level. */
1069 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
1070 qdepth += quotelen;
1071 return qdepth;
1072#endif /* !HAVE_REGEX_H */
1073}
1074
1075/* a_line and b_line are lines of text. The quotation part of a_line is
1076 * the first a_quote characters. Check that the quotation part of
1077 * b_line is the same. */
1078bool quotes_match(const char *a_line, size_t a_quote, const char
1079 *b_line)
1080{
1081 /* Here is the assumption about a_quote. */
1082 assert(a_quote == quote_length(a_line));
1083
1084 return (a_quote == quote_length(b_line) &&
1085 strncmp(a_line, b_line, a_quote) == 0);
1086}
1087
1088/* We assume a_line and b_line have no quote part. Then, we return
1089 * whether b_line could follow a_line in a paragraph. */
1090bool indents_match(const char *a_line, size_t a_indent, const char
1091 *b_line, size_t b_indent)
1092{
1093 assert(a_indent == indent_length(a_line));
1094 assert(b_indent == indent_length(b_line));
1095
1096 return (b_indent <= a_indent &&
1097 strncmp(a_line, b_line, b_indent) == 0);
1098}
1099
1100/* Is foo the beginning of a paragraph?
1101 *
1102 * A line of text consists of a "quote part", followed by an
1103 * "indentation part", followed by text. The functions quote_length()
1104 * and indent_length() calculate these parts.
1105 *
1106 * A line is "part of a paragraph" if it has a part not in the quote
1107 * part or the indentation.
1108 *
1109 * A line is "the beginning of a paragraph" if it is part of a
1110 * paragraph and
1111 * 1) it is the top line of the file, or
1112 * 2) the line above it is not part of a paragraph, or
1113 * 3) the line above it does not have precisely the same quote
1114 * part, or
1115 * 4) the indentation of this line is not an initial substring of
1116 * the indentation of the previous line, or
1117 * 5) this line has no quote part and some indentation, and
1118 * autoindent isn't turned on.
1119 * The reason for number 5) is that if autoindent isn't turned on,
1120 * then an indented line is expected to start a paragraph, as in
1121 * books. Thus, nano can justify an indented paragraph only if
1122 * autoindent is turned on. */
1123bool begpar(const filestruct *const foo)
1124{
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +00001125 size_t quote_len, indent_len, temp_id_len;
1126
1127 if (foo == NULL)
1128 return FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001129
1130 /* Case 1). */
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +00001131 if (foo == openfile->fileage)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001132 return TRUE;
1133
1134 quote_len = quote_length(foo->data);
1135 indent_len = indent_length(foo->data + quote_len);
1136
1137 /* Not part of a paragraph. */
1138 if (foo->data[quote_len + indent_len] == '\0')
1139 return FALSE;
1140
1141 /* Case 3). */
1142 if (!quotes_match(foo->data, quote_len, foo->prev->data))
1143 return TRUE;
1144
1145 temp_id_len = indent_length(foo->prev->data + quote_len);
1146
1147 /* Case 2) or 5) or 4). */
1148 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
1149 (quote_len == 0 && indent_len > 0
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001150#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001151 && !ISSET(AUTOINDENT)
1152#endif
1153 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
1154 foo->data + quote_len, indent_len))
1155 return TRUE;
1156
1157 return FALSE;
1158}
1159
1160/* Is foo inside a paragraph? */
1161bool inpar(const filestruct *const foo)
1162{
1163 size_t quote_len;
1164
1165 if (foo == NULL)
1166 return FALSE;
1167
1168 quote_len = quote_length(foo->data);
1169
David Lawrence Ramsey21014032005-11-09 20:33:42 +00001170 return (foo->data[quote_len + indent_length(foo->data +
1171 quote_len)] != '\0');
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001172}
1173
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001174/* Move the next par_len lines, starting with first_line, into the
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001175 * justify buffer, leaving copies of those lines in place. Assume that
1176 * par_len is greater than zero, and that there are enough lines after
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001177 * first_line. */
1178void backup_lines(filestruct *first_line, size_t par_len)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001179{
1180 filestruct *top = first_line;
1181 /* The top of the paragraph we're backing up. */
1182 filestruct *bot = first_line;
1183 /* The bottom of the paragraph we're backing up. */
1184 size_t i;
1185 /* Generic loop variable. */
1186 size_t current_x_save = openfile->current_x;
1187 ssize_t fl_lineno_save = first_line->lineno;
1188 ssize_t edittop_lineno_save = openfile->edittop->lineno;
1189 ssize_t current_lineno_save = openfile->current->lineno;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001190#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001191 bool old_mark_set = openfile->mark_set;
1192 ssize_t mb_lineno_save = 0;
1193 size_t mark_begin_x_save = 0;
1194
1195 if (old_mark_set) {
1196 mb_lineno_save = openfile->mark_begin->lineno;
1197 mark_begin_x_save = openfile->mark_begin_x;
1198 }
1199#endif
1200
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001201 /* par_len will be one greater than the number of lines between
1202 * current and filebot if filebot is the last line in the
1203 * paragraph. */
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001204 assert(par_len > 0 && openfile->current->lineno + par_len <=
David Lawrence Ramsey24777c02005-12-01 05:49:08 +00001205 openfile->filebot->lineno + 1);
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001206
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001207 /* Move bot down par_len lines to the line after the last line of
1208 * the paragraph, if there is one. */
1209 for (i = par_len; i > 0 && bot != openfile->filebot; i--)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001210 bot = bot->next;
1211
1212 /* Move the paragraph from the current buffer's filestruct to the
1213 * justify buffer. */
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001214 move_to_filestruct(&jusbuffer, &jusbottom, top, 0, bot,
David Lawrence Ramseyf0575cf2005-11-09 23:27:51 +00001215 (i == 1 && bot == openfile->filebot) ? strlen(bot->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001216
1217 /* Copy the paragraph back to the current buffer's filestruct from
1218 * the justify buffer. */
1219 copy_from_filestruct(jusbuffer, jusbottom);
1220
1221 /* Move upward from the last line of the paragraph to the first
1222 * line, putting first_line, edittop, current, and mark_begin at the
1223 * same lines in the copied paragraph that they had in the original
1224 * paragraph. */
David Lawrence Ramsey5d6f1272005-11-10 03:32:59 +00001225 if (openfile->current != openfile->fileage)
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001226 top = openfile->current->prev;
1227 else
1228 top = openfile->current;
David Lawrence Ramseye8d505b2005-11-10 03:40:45 +00001229 for (i = par_len; i > 0 && top != NULL; i--) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001230 if (top->lineno == fl_lineno_save)
1231 first_line = top;
1232 if (top->lineno == edittop_lineno_save)
1233 openfile->edittop = top;
1234 if (top->lineno == current_lineno_save)
1235 openfile->current = top;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001236#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001237 if (old_mark_set && top->lineno == mb_lineno_save) {
1238 openfile->mark_begin = top;
1239 openfile->mark_begin_x = mark_begin_x_save;
1240 }
1241#endif
1242 top = top->prev;
1243 }
1244
1245 /* Put current_x at the same place in the copied paragraph that it
1246 * had in the original paragraph. */
1247 openfile->current_x = current_x_save;
1248
1249 set_modified();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001250}
1251
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001252/* Find the beginning of the current paragraph if we're in one, or the
1253 * beginning of the next paragraph if we're not. Afterwards, save the
1254 * quote length and paragraph length in *quote and *par. Return TRUE if
1255 * we found a paragraph, or FALSE if there was an error or we didn't
1256 * find a paragraph.
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001257 *
1258 * See the comment at begpar() for more about when a line is the
1259 * beginning of a paragraph. */
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001260bool find_paragraph(size_t *const quote, size_t *const par)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001261{
1262 size_t quote_len;
1263 /* Length of the initial quotation of the paragraph we search
1264 * for. */
1265 size_t par_len;
1266 /* Number of lines in the paragraph we search for. */
1267 filestruct *current_save;
1268 /* The line at the beginning of the paragraph we search for. */
1269 ssize_t current_y_save;
1270 /* The y-coordinate at the beginning of the paragraph we search
1271 * for. */
1272
1273#ifdef HAVE_REGEX_H
1274 if (quoterc != 0) {
1275 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
1276 return FALSE;
1277 }
1278#endif
1279
1280 assert(openfile->current != NULL);
1281
David Lawrence Ramsey1be131a2005-11-11 03:55:52 +00001282 /* If we're at the end of the last line of the file, it means that
1283 * there aren't any paragraphs left, so get out. */
1284 if (openfile->current == openfile->filebot && openfile->current_x ==
1285 strlen(openfile->filebot->data))
1286 return FALSE;
1287
1288 /* If the current line isn't in a paragraph, move forward to the
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001289 * last line of the next paragraph, if any. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001290 if (!inpar(openfile->current)) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001291 do_para_end(FALSE);
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001292
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001293 /* If we end up past the beginning of the line, it means that
1294 * we're at the end of the last line of the file, and the line
1295 * isn't blank, in which case the last line of the file is the
1296 * last line of the next paragraph.
1297 *
1298 * Otherwise, if we end up on a line that's in a paragraph, it
1299 * means that we're on the line after the last line of the next
1300 * paragraph, in which case we should move back to the last line
1301 * of the next paragraph. */
1302 if (openfile->current_x == 0) {
1303 if (!inpar(openfile->current->prev))
1304 return FALSE;
1305 if (openfile->current != openfile->fileage)
1306 openfile->current = openfile->current->prev;
1307 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001308 }
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001309
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001310 /* If the current line isn't the first line of the paragraph, move
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001311 * back to the first line of the paragraph. */
1312 if (!begpar(openfile->current))
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001313 do_para_begin(FALSE);
1314
1315 /* Now current is the first line of the paragraph. Set quote_len to
1316 * the quotation length of that line, and set par_len to the number
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001317 * of lines in this paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001318 quote_len = quote_length(openfile->current->data);
1319 current_save = openfile->current;
1320 current_y_save = openfile->current_y;
1321 do_para_end(FALSE);
1322 par_len = openfile->current->lineno - current_save->lineno;
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001323
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001324 /* If we end up past the beginning of the line, it means that we're
1325 * at the end of the last line of the file, and the line isn't
1326 * blank, in which case the last line of the file is part of the
1327 * paragraph. */
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00001328 if (openfile->current_x > 0)
1329 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001330 openfile->current = current_save;
1331 openfile->current_y = current_y_save;
1332
1333 /* Save the values of quote_len and par_len. */
1334 assert(quote != NULL && par != NULL);
1335
1336 *quote = quote_len;
1337 *par = par_len;
1338
1339 return TRUE;
1340}
1341
1342/* If full_justify is TRUE, justify the entire file. Otherwise, justify
1343 * the current paragraph. */
1344void do_justify(bool full_justify)
1345{
1346 filestruct *first_par_line = NULL;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001347 /* Will be the first line of the justified paragraph(s), if any.
1348 * For restoring after unjustify. */
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001349 filestruct *last_par_line = NULL;
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001350 /* Will be the line after the last line of the justified
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001351 * paragraph(s), if any. Also for restoring after unjustify. */
David Lawrence Ramsey82b5deb2005-11-10 06:07:57 +00001352 bool filebot_inpar = FALSE;
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001353 /* Whether the text at filebot is part of the current
1354 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001355
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00001356 /* We save these variables to be restored if the user
1357 * unjustifies. */
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00001358 filestruct *edittop_save = openfile->edittop;
1359 filestruct *current_save = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001360 size_t current_x_save = openfile->current_x;
1361 size_t pww_save = openfile->placewewant;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001362 size_t totsize_save = openfile->totsize;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001363#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001364 filestruct *mark_begin_save = openfile->mark_begin;
1365 size_t mark_begin_x_save = openfile->mark_begin_x;
1366#endif
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00001367 bool modified_save = openfile->modified;
1368
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001369 int kbinput;
1370 bool meta_key, func_key, s_or_t, ran_func, finished;
1371
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001372 /* Move to the beginning of the current line, so that justifying at
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00001373 * the end of the last line of the file, if that line isn't blank,
1374 * will work the first time through. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001375 openfile->current_x = 0;
1376
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001377 /* If we're justifying the entire file, start at the beginning. */
1378 if (full_justify)
1379 openfile->current = openfile->fileage;
1380
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001381 while (TRUE) {
1382 size_t i;
1383 /* Generic loop variable. */
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001384 filestruct *curr_first_par_line;
1385 /* The first line of the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001386 size_t quote_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001387 /* Length of the initial quotation of the current
1388 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001389 size_t indent_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001390 /* Length of the initial indentation of the current
1391 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001392 size_t par_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001393 /* Number of lines in the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001394 ssize_t break_pos;
1395 /* Where we will break lines. */
1396 char *indent_string;
1397 /* The first indentation that doesn't match the initial
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001398 * indentation of the current paragraph. This is put at the
1399 * beginning of every line broken off the first justified
1400 * line of the paragraph. Note that this works because a
1401 * paragraph can only contain two indentations at most: the
1402 * initial one, and a different one starting on a line after
1403 * the first. See the comment at begpar() for more about
1404 * when a line is part of a paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001405
1406 /* Find the first line of the paragraph to be justified. That
1407 * is the start of this paragraph if we're in one, or the start
1408 * of the next otherwise. Save the quote length and paragraph
1409 * length (number of lines). Don't refresh the screen yet,
1410 * since we'll do that after we justify.
1411 *
1412 * If the search failed, we do one of two things. If we're
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00001413 * justifying the whole file, and we've found at least one
1414 * paragraph, it means that we should justify all the way to the
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001415 * last line of the file, so set the last line of the text to be
1416 * justified to the last line of the file and break out of the
1417 * loop. Otherwise, it means that there are no paragraph(s) to
1418 * justify, so refresh the screen and get out. */
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001419 if (!find_paragraph(&quote_len, &par_len)) {
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00001420 if (full_justify && first_par_line != NULL) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001421 last_par_line = openfile->filebot;
1422 break;
1423 } else {
1424 edit_refresh();
1425 return;
1426 }
1427 }
1428
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001429 /* par_len will be one greater than the number of lines between
1430 * current and filebot if filebot is the last line in the
1431 * paragraph. Set filebot_inpar to TRUE if this is the case. */
1432 filebot_inpar = (openfile->current->lineno + par_len ==
1433 openfile->filebot->lineno + 1);
1434
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001435 /* If we haven't already done it, move the original paragraph(s)
1436 * to the justify buffer, splice a copy of the original
1437 * paragraph(s) into the file in the same place, and set
1438 * first_par_line to the first line of the copy. */
1439 if (first_par_line == NULL) {
1440 backup_lines(openfile->current, full_justify ?
David Lawrence Ramsey53f641f2005-11-10 21:57:56 +00001441 openfile->filebot->lineno - openfile->current->lineno +
1442 ((openfile->filebot->data[0] != '\0') ? 1 : 0) :
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001443 par_len);
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001444 first_par_line = openfile->current;
1445 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001446
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001447 /* Set curr_first_par_line to the first line of the current
1448 * paragraph. */
1449 curr_first_par_line = openfile->current;
1450
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001451 /* Initialize indent_string to a blank string. */
1452 indent_string = mallocstrcpy(NULL, "");
1453
1454 /* Find the first indentation in the paragraph that doesn't
1455 * match the indentation of the first line, and save it in
1456 * indent_string. If all the indentations are the same, save
1457 * the indentation of the first line in indent_string. */
1458 {
1459 const filestruct *indent_line = openfile->current;
1460 bool past_first_line = FALSE;
1461
1462 for (i = 0; i < par_len; i++) {
1463 indent_len = quote_len +
1464 indent_length(indent_line->data + quote_len);
1465
1466 if (indent_len != strlen(indent_string)) {
1467 indent_string = mallocstrncpy(indent_string,
1468 indent_line->data, indent_len + 1);
1469 indent_string[indent_len] = '\0';
1470
1471 if (past_first_line)
1472 break;
1473 }
1474
1475 if (indent_line == openfile->current)
1476 past_first_line = TRUE;
1477
1478 indent_line = indent_line->next;
1479 }
1480 }
1481
1482 /* Now tack all the lines of the paragraph together, skipping
1483 * the quoting and indentation on all lines after the first. */
1484 for (i = 0; i < par_len - 1; i++) {
1485 filestruct *next_line = openfile->current->next;
1486 size_t line_len = strlen(openfile->current->data);
1487 size_t next_line_len =
1488 strlen(openfile->current->next->data);
1489
1490 indent_len = quote_len +
1491 indent_length(openfile->current->next->data +
1492 quote_len);
1493
1494 next_line_len -= indent_len;
1495 openfile->totsize -= indent_len;
1496
1497 /* We're just about to tack the next line onto this one. If
1498 * this line isn't empty, make sure it ends in a space. */
1499 if (line_len > 0 &&
1500 openfile->current->data[line_len - 1] != ' ') {
1501 line_len++;
1502 openfile->current->data =
1503 charealloc(openfile->current->data,
1504 line_len + 1);
1505 openfile->current->data[line_len - 1] = ' ';
1506 openfile->current->data[line_len] = '\0';
1507 openfile->totsize++;
1508 }
1509
1510 openfile->current->data =
1511 charealloc(openfile->current->data, line_len +
1512 next_line_len + 1);
1513 strcat(openfile->current->data, next_line->data +
1514 indent_len);
1515
David Lawrence Ramsey9bedc4b2005-11-09 19:51:48 +00001516 /* Don't destroy edittop or filebot! */
David Lawrence Ramsey32bd29e2005-11-09 03:44:23 +00001517 if (next_line == openfile->edittop)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001518 openfile->edittop = openfile->current;
David Lawrence Ramsey9bedc4b2005-11-09 19:51:48 +00001519 if (next_line == openfile->filebot)
1520 openfile->filebot = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001521
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001522#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001523 /* Adjust the mark coordinates to compensate for the change
1524 * in the next line. */
1525 if (openfile->mark_set && openfile->mark_begin ==
1526 next_line) {
1527 openfile->mark_begin = openfile->current;
1528 openfile->mark_begin_x += line_len - indent_len;
1529 }
1530#endif
1531
1532 unlink_node(next_line);
1533 delete_node(next_line);
1534
1535 /* If we've removed the next line, we need to go through
1536 * this line again. */
1537 i--;
1538
1539 par_len--;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001540 openfile->totsize--;
1541 }
1542
1543 /* Call justify_format() on the paragraph, which will remove
1544 * excess spaces from it and change all blank characters to
1545 * spaces. */
1546 justify_format(openfile->current, quote_len +
1547 indent_length(openfile->current->data + quote_len));
1548
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001549 while (par_len > 0 && strlenpt(openfile->current->data) >
1550 fill) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001551 size_t line_len = strlen(openfile->current->data);
1552
1553 indent_len = strlen(indent_string);
1554
1555 /* If this line is too long, try to wrap it to the next line
1556 * to make it short enough. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001557 break_pos = break_line(openfile->current->data + indent_len,
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001558 fill - strnlenpt(openfile->current->data, indent_len)
1559#ifndef DISABLE_HELP
1560 , FALSE
1561#endif
1562 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001563
1564 /* We can't break the line, or don't need to, so get out. */
1565 if (break_pos == -1 || break_pos + indent_len == line_len)
1566 break;
1567
1568 /* Move forward to the character after the indentation and
1569 * just after the space. */
1570 break_pos += indent_len + 1;
1571
1572 assert(break_pos <= line_len);
1573
1574 /* Make a new line, and copy the text after where we're
1575 * going to break this line to the beginning of the new
1576 * line. */
1577 splice_node(openfile->current,
1578 make_new_node(openfile->current),
1579 openfile->current->next);
1580
1581 /* If this paragraph is non-quoted, and autoindent isn't
1582 * turned on, set the indentation length to zero so that the
1583 * indentation is treated as part of the line. */
1584 if (quote_len == 0
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001585#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001586 && !ISSET(AUTOINDENT)
1587#endif
1588 )
1589 indent_len = 0;
1590
1591 /* Copy the text after where we're going to break the
1592 * current line to the next line. */
1593 openfile->current->next->data = charalloc(indent_len + 1 +
1594 line_len - break_pos);
1595 strncpy(openfile->current->next->data, indent_string,
1596 indent_len);
1597 strcpy(openfile->current->next->data + indent_len,
1598 openfile->current->data + break_pos);
1599
1600 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001601 openfile->totsize += indent_len + 1;
1602
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001603#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001604 /* Adjust the mark coordinates to compensate for the change
1605 * in the current line. */
1606 if (openfile->mark_set && openfile->mark_begin ==
1607 openfile->current && openfile->mark_begin_x >
1608 break_pos) {
1609 openfile->mark_begin = openfile->current->next;
1610 openfile->mark_begin_x -= break_pos - indent_len;
1611 }
1612#endif
1613
1614 /* Break the current line. */
1615 null_at(&openfile->current->data, break_pos);
1616
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001617 /* If the current line is the last line of the file, move
David Lawrence Ramseyb885c9c2005-11-10 05:20:25 +00001618 * the last line of the file down to the next line. */
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001619 if (openfile->filebot == openfile->current)
1620 openfile->filebot = openfile->filebot->next;
1621
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001622 /* Go to the next line. */
1623 par_len--;
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001624 openfile->current_y++;
1625 openfile->current = openfile->current->next;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001626 }
1627
1628 /* We're done breaking lines, so we don't need indent_string
1629 * anymore. */
1630 free(indent_string);
1631
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001632 /* Go to the next line, if possible. If there is no next line,
1633 * move to the end of the current line. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001634 if (openfile->current != openfile->filebot) {
1635 openfile->current_y++;
1636 openfile->current = openfile->current->next;
1637 } else
1638 openfile->current_x = strlen(openfile->current->data);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001639
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001640 /* Renumber the lines of the now-justified current paragraph,
1641 * since both find_paragraph() and edit_refresh() need the line
1642 * numbers to be right. */
1643 renumber(curr_first_par_line);
David Lawrence Ramseyad1b64c2005-11-29 19:00:09 +00001644
1645 /* We've just finished justifying the paragraph. If we're not
1646 * justifying the entire file, break out of the loop.
1647 * Otherwise, continue the loop so that we justify all the
1648 * paragraphs in the file. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001649 if (!full_justify)
1650 break;
1651 }
1652
1653 /* We are now done justifying the paragraph or the file, so clean
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001654 * up. current_y and totsize have been maintained above. If we
David Lawrence Ramseyad1b64c2005-11-29 19:00:09 +00001655 * actually justified something, set last_par_line to the new end of
1656 * the paragraph. */
1657 if (first_par_line != NULL)
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001658 last_par_line = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001659
1660 edit_refresh();
1661
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00001662#ifndef NANO_TINY
David Lawrence Ramsey1c5af642006-05-10 15:15:06 +00001663 /* We're going to set jump_buf so that we return here after a
1664 * SIGWINCH instead of to main(). Indicate this. */
1665 jump_buf_main = FALSE;
1666
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00001667 /* Return here after a SIGWINCH. */
David Lawrence Ramsey1c5af642006-05-10 15:15:06 +00001668 sigsetjmp(jump_buf, 1);
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00001669#endif
1670
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001671 statusbar(_("Can now UnJustify!"));
1672
1673 /* If constant cursor position display is on, make sure the current
1674 * cursor position will be properly displayed on the statusbar. */
1675 if (ISSET(CONST_UPDATE))
1676 do_cursorpos(TRUE);
1677
1678 /* Display the shortcut list with UnJustify. */
1679 shortcut_init(TRUE);
1680 display_main_list();
1681
1682 /* Now get a keystroke and see if it's unjustify. If not, put back
1683 * the keystroke and return. */
1684 kbinput = do_input(&meta_key, &func_key, &s_or_t, &ran_func,
1685 &finished, FALSE);
1686
David Lawrence Ramseyb22c80a2006-05-06 13:41:59 +00001687 if (s_or_t && kbinput == NANO_UNJUSTIFY_KEY) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001688 /* Splice the justify buffer back into the file, but only if we
1689 * actually justified something. */
1690 if (first_par_line != NULL) {
1691 filestruct *top_save;
1692
1693 /* Partition the filestruct so that it contains only the
1694 * text of the justified paragraph. */
1695 filepart = partition_filestruct(first_par_line, 0,
David Lawrence Ramseyccd1b7b2005-11-18 20:21:48 +00001696 last_par_line, filebot_inpar ?
1697 strlen(last_par_line->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001698
1699 /* Remove the text of the justified paragraph, and
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001700 * replace it with the text in the justify buffer. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001701 free_filestruct(openfile->fileage);
1702 openfile->fileage = jusbuffer;
1703 openfile->filebot = jusbottom;
1704
1705 top_save = openfile->fileage;
1706
1707 /* Unpartition the filestruct so that it contains all the
1708 * text again. Note that the justified paragraph has been
1709 * replaced with the unjustified paragraph. */
1710 unpartition_filestruct(&filepart);
1711
1712 /* Renumber starting with the beginning line of the old
1713 * partition. */
1714 renumber(top_save);
1715
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001716 /* Restore the justify we just did (ungrateful user!). */
1717 openfile->edittop = edittop_save;
1718 openfile->current = current_save;
1719 openfile->current_x = current_x_save;
1720 openfile->placewewant = pww_save;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001721 openfile->totsize = totsize_save;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001722#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001723 if (openfile->mark_set) {
1724 openfile->mark_begin = mark_begin_save;
1725 openfile->mark_begin_x = mark_begin_x_save;
1726 }
1727#endif
1728 openfile->modified = modified_save;
1729
1730 /* Clear the justify buffer. */
1731 jusbuffer = NULL;
1732
1733 if (!openfile->modified)
1734 titlebar(NULL);
1735 edit_refresh();
1736 }
1737 } else {
1738 unget_kbinput(kbinput, meta_key, func_key);
1739
1740 /* Blow away the text in the justify buffer. */
1741 free_filestruct(jusbuffer);
1742 jusbuffer = NULL;
1743 }
1744
1745 blank_statusbar();
1746
1747 /* Display the shortcut list with UnCut. */
1748 shortcut_init(FALSE);
1749 display_main_list();
1750}
1751
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001752/* Justify the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001753void do_justify_void(void)
1754{
1755 do_justify(FALSE);
1756}
1757
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001758/* Justify the entire file. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001759void do_full_justify(void)
1760{
1761 do_justify(TRUE);
1762}
1763#endif /* !DISABLE_JUSTIFY */
1764
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001765#ifndef DISABLE_SPELLER
1766/* A word is misspelled in the file. Let the user replace it. We
1767 * return FALSE if the user cancels. */
1768bool do_int_spell_fix(const char *word)
1769{
1770 char *save_search, *save_replace;
1771 size_t match_len, current_x_save = openfile->current_x;
1772 size_t pww_save = openfile->placewewant;
1773 filestruct *edittop_save = openfile->edittop;
1774 filestruct *current_save = openfile->current;
1775 /* Save where we are. */
1776 bool canceled = FALSE;
1777 /* The return value. */
1778 bool case_sens_set = ISSET(CASE_SENSITIVE);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001779#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001780 bool backwards_search_set = ISSET(BACKWARDS_SEARCH);
1781#endif
1782#ifdef HAVE_REGEX_H
1783 bool regexp_set = ISSET(USE_REGEXP);
1784#endif
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001785#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001786 bool old_mark_set = openfile->mark_set;
1787 bool added_magicline = FALSE;
1788 /* Whether we added a magicline after filebot. */
1789 bool right_side_up = FALSE;
1790 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
1791 * FALSE if (current, current_x) is. */
1792 filestruct *top, *bot;
1793 size_t top_x, bot_x;
1794#endif
1795
1796 /* Make sure spell-check is case sensitive. */
1797 SET(CASE_SENSITIVE);
1798
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001799#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001800 /* Make sure spell-check goes forward only. */
1801 UNSET(BACKWARDS_SEARCH);
1802#endif
1803#ifdef HAVE_REGEX_H
1804 /* Make sure spell-check doesn't use regular expressions. */
1805 UNSET(USE_REGEXP);
1806#endif
1807
1808 /* Save the current search/replace strings. */
1809 search_init_globals();
1810 save_search = last_search;
1811 save_replace = last_replace;
1812
1813 /* Set the search/replace strings to the misspelled word. */
1814 last_search = mallocstrcpy(NULL, word);
1815 last_replace = mallocstrcpy(NULL, word);
1816
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001817#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001818 if (old_mark_set) {
1819 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00001820 * contains only the marked text; if the NO_NEWLINES flag isn't
1821 * set, keep track of whether the text will have a magicline
1822 * added when we're done correcting misspelled words; and
1823 * turn the mark off. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001824 mark_order((const filestruct **)&top, &top_x,
1825 (const filestruct **)&bot, &bot_x, &right_side_up);
1826 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00001827 if (!ISSET(NO_NEWLINES))
1828 added_magicline = (openfile->filebot->data[0] != '\0');
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001829 openfile->mark_set = FALSE;
1830 }
1831#endif
1832
1833 /* Start from the top of the file. */
1834 openfile->edittop = openfile->fileage;
1835 openfile->current = openfile->fileage;
1836 openfile->current_x = (size_t)-1;
1837 openfile->placewewant = 0;
1838
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001839 /* Find the first whole occurrence of word. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001840 findnextstr_wrap_reset();
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001841 while (findnextstr(TRUE, FALSE, openfile->fileage, 0, word,
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001842 &match_len)) {
1843 if (is_whole_word(openfile->current_x, openfile->current->data,
1844 word)) {
1845 size_t xpt = xplustabs();
1846 char *exp_word = display_string(openfile->current->data,
1847 xpt, strnlenpt(openfile->current->data,
1848 openfile->current_x + match_len) - xpt, FALSE);
1849
1850 edit_refresh();
1851
1852 do_replace_highlight(TRUE, exp_word);
1853
1854 /* Allow all instances of the word to be corrected. */
David Lawrence Ramsey9d8c2842006-02-07 21:11:05 +00001855 canceled = (do_prompt(FALSE,
1856#ifndef DISABLE_TABCOMP
1857 TRUE,
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001858#endif
David Lawrence Ramsey9d8c2842006-02-07 21:11:05 +00001859 spell_list, word,
1860#ifndef NANO_TINY
1861 NULL,
1862#endif
David Lawrence Ramsey68160072006-02-18 21:32:29 +00001863 edit_refresh, _("Edit a replacement")) == -1);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001864
1865 do_replace_highlight(FALSE, exp_word);
1866
1867 free(exp_word);
1868
1869 if (!canceled && strcmp(word, answer) != 0) {
1870 openfile->current_x--;
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001871 do_replace_loop(TRUE, &canceled, openfile->current,
1872 &openfile->current_x, word);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001873 }
1874
1875 break;
1876 }
1877 }
1878
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001879#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001880 if (old_mark_set) {
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00001881 /* If the mark was on, the NO_NEWLINES flag isn't set, and we
1882 * added a magicline, remove it now. */
1883 if (!ISSET(NO_NEWLINES) && added_magicline)
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001884 remove_magicline();
1885
1886 /* Put the beginning and the end of the mark at the beginning
1887 * and the end of the spell-checked text. */
1888 if (openfile->fileage == openfile->filebot)
1889 bot_x += top_x;
1890 if (right_side_up) {
1891 openfile->mark_begin_x = top_x;
1892 current_x_save = bot_x;
1893 } else {
1894 current_x_save = top_x;
1895 openfile->mark_begin_x = bot_x;
1896 }
1897
1898 /* Unpartition the filestruct so that it contains all the text
1899 * again, and turn the mark back on. */
1900 unpartition_filestruct(&filepart);
1901 openfile->mark_set = TRUE;
1902 }
1903#endif
1904
1905 /* Restore the search/replace strings. */
1906 free(last_search);
1907 last_search = save_search;
1908 free(last_replace);
1909 last_replace = save_replace;
1910
1911 /* Restore where we were. */
1912 openfile->edittop = edittop_save;
1913 openfile->current = current_save;
1914 openfile->current_x = current_x_save;
1915 openfile->placewewant = pww_save;
1916
1917 /* Restore case sensitivity setting. */
1918 if (!case_sens_set)
1919 UNSET(CASE_SENSITIVE);
1920
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001921#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001922 /* Restore search/replace direction. */
1923 if (backwards_search_set)
1924 SET(BACKWARDS_SEARCH);
1925#endif
1926#ifdef HAVE_REGEX_H
1927 /* Restore regular expression usage setting. */
1928 if (regexp_set)
1929 SET(USE_REGEXP);
1930#endif
1931
1932 return !canceled;
1933}
1934
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001935/* Internal (integrated) spell checking using the spell program,
1936 * filtered through the sort and uniq programs. Return NULL for normal
1937 * termination, and the error string otherwise. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001938const char *do_int_speller(const char *tempfile_name)
1939{
1940 char *read_buff, *read_buff_ptr, *read_buff_word;
1941 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
1942 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
1943 pid_t pid_spell, pid_sort, pid_uniq;
1944 int spell_status, sort_status, uniq_status;
1945
1946 /* Create all three pipes up front. */
1947 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 ||
1948 pipe(uniq_fd) == -1)
1949 return _("Could not create pipe");
1950
1951 statusbar(_("Creating misspelled word list, please wait..."));
1952
1953 /* A new process to run spell in. */
1954 if ((pid_spell = fork()) == 0) {
1955 /* Child continues (i.e, future spell process). */
1956 close(spell_fd[0]);
1957
1958 /* Replace the standard input with the temp file. */
1959 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1960 goto close_pipes_and_exit;
1961
1962 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1963 goto close_pipes_and_exit;
1964
1965 close(tempfile_fd);
1966
1967 /* Send spell's standard output to the pipe. */
1968 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1969 goto close_pipes_and_exit;
1970
1971 close(spell_fd[1]);
1972
David Lawrence Ramsey3239ff22005-11-29 20:01:06 +00001973 /* Start the spell program; we are using $PATH. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001974 execlp("spell", "spell", NULL);
1975
1976 /* This should not be reached if spell is found. */
1977 exit(1);
1978 }
1979
1980 /* Parent continues here. */
1981 close(spell_fd[1]);
1982
1983 /* A new process to run sort in. */
1984 if ((pid_sort = fork()) == 0) {
1985 /* Child continues (i.e, future spell process). Replace the
1986 * standard input with the standard output of the old pipe. */
1987 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1988 goto close_pipes_and_exit;
1989
1990 close(spell_fd[0]);
1991
1992 /* Send sort's standard output to the new pipe. */
1993 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1994 goto close_pipes_and_exit;
1995
1996 close(sort_fd[1]);
1997
1998 /* Start the sort program. Use -f to remove mixed case. If
1999 * this isn't portable, let me know. */
2000 execlp("sort", "sort", "-f", NULL);
2001
2002 /* This should not be reached if sort is found. */
2003 exit(1);
2004 }
2005
2006 close(spell_fd[0]);
2007 close(sort_fd[1]);
2008
2009 /* A new process to run uniq in. */
2010 if ((pid_uniq = fork()) == 0) {
2011 /* Child continues (i.e, future uniq process). Replace the
2012 * standard input with the standard output of the old pipe. */
2013 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
2014 goto close_pipes_and_exit;
2015
2016 close(sort_fd[0]);
2017
2018 /* Send uniq's standard output to the new pipe. */
2019 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2020 goto close_pipes_and_exit;
2021
2022 close(uniq_fd[1]);
2023
2024 /* Start the uniq program; we are using PATH. */
2025 execlp("uniq", "uniq", NULL);
2026
2027 /* This should not be reached if uniq is found. */
2028 exit(1);
2029 }
2030
2031 close(sort_fd[0]);
2032 close(uniq_fd[1]);
2033
2034 /* The child process was not forked successfully. */
2035 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
2036 close(uniq_fd[0]);
2037 return _("Could not fork");
2038 }
2039
2040 /* Get the system pipe buffer size. */
2041 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
2042 close(uniq_fd[0]);
2043 return _("Could not get size of pipe buffer");
2044 }
2045
2046 /* Read in the returned spelling errors. */
2047 read_buff_read = 0;
2048 read_buff_size = pipe_buff_size + 1;
2049 read_buff = read_buff_ptr = charalloc(read_buff_size);
2050
2051 while ((bytesread = read(uniq_fd[0], read_buff_ptr,
2052 pipe_buff_size)) > 0) {
2053 read_buff_read += bytesread;
2054 read_buff_size += pipe_buff_size;
2055 read_buff = read_buff_ptr = charealloc(read_buff,
2056 read_buff_size);
2057 read_buff_ptr += read_buff_read;
2058 }
2059
2060 *read_buff_ptr = '\0';
2061 close(uniq_fd[0]);
2062
2063 /* Process the spelling errors. */
2064 read_buff_word = read_buff_ptr = read_buff;
2065
2066 while (*read_buff_ptr != '\0') {
2067 if ((*read_buff_ptr == '\r') || (*read_buff_ptr == '\n')) {
2068 *read_buff_ptr = '\0';
2069 if (read_buff_word != read_buff_ptr) {
2070 if (!do_int_spell_fix(read_buff_word)) {
2071 read_buff_word = read_buff_ptr;
2072 break;
2073 }
2074 }
2075 read_buff_word = read_buff_ptr + 1;
2076 }
2077 read_buff_ptr++;
2078 }
2079
2080 /* Special case: the last word doesn't end with '\r' or '\n'. */
2081 if (read_buff_word != read_buff_ptr)
2082 do_int_spell_fix(read_buff_word);
2083
2084 free(read_buff);
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002085 search_replace_abort();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002086 edit_refresh();
2087
2088 /* Process the end of the spell process. */
2089 waitpid(pid_spell, &spell_status, 0);
2090 waitpid(pid_sort, &sort_status, 0);
2091 waitpid(pid_uniq, &uniq_status, 0);
2092
2093 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
2094 return _("Error invoking \"spell\"");
2095
2096 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
2097 return _("Error invoking \"sort -f\"");
2098
2099 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
2100 return _("Error invoking \"uniq\"");
2101
2102 /* Otherwise... */
2103 return NULL;
2104
2105 close_pipes_and_exit:
2106 /* Don't leak any handles. */
2107 close(tempfile_fd);
2108 close(spell_fd[0]);
2109 close(spell_fd[1]);
2110 close(sort_fd[0]);
2111 close(sort_fd[1]);
2112 close(uniq_fd[0]);
2113 close(uniq_fd[1]);
2114 exit(1);
2115}
2116
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002117/* External (alternate) spell checking. Return NULL for normal
2118 * termination, and the error string otherwise. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002119const char *do_alt_speller(char *tempfile_name)
2120{
2121 int alt_spell_status;
2122 size_t current_x_save = openfile->current_x;
2123 size_t pww_save = openfile->placewewant;
2124 ssize_t current_y_save = openfile->current_y;
2125 ssize_t lineno_save = openfile->current->lineno;
2126 pid_t pid_spell;
2127 char *ptr;
2128 static int arglen = 3;
2129 static char **spellargs = NULL;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002130#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002131 bool old_mark_set = openfile->mark_set;
2132 bool added_magicline = FALSE;
2133 /* Whether we added a magicline after filebot. */
2134 bool right_side_up = FALSE;
2135 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
2136 * FALSE if (current, current_x) is. */
2137 filestruct *top, *bot;
2138 size_t top_x, bot_x;
2139 ssize_t mb_lineno_save = 0;
2140 /* We're going to close the current file, and open the output of
2141 * the alternate spell command. The line that mark_begin points
2142 * to will be freed, so we save the line number and restore it
2143 * afterwards. */
2144 size_t totsize_save = openfile->totsize;
2145 /* Our saved value of totsize, used when we spell-check a marked
2146 * selection. */
2147
2148 if (old_mark_set) {
2149 /* If the mark is on, save the number of the line it starts on,
2150 * and then turn the mark off. */
2151 mb_lineno_save = openfile->mark_begin->lineno;
2152 openfile->mark_set = FALSE;
2153 }
2154#endif
2155
2156 endwin();
2157
2158 /* Set up an argument list to pass execvp(). */
2159 if (spellargs == NULL) {
2160 spellargs = (char **)nmalloc(arglen * sizeof(char *));
2161
2162 spellargs[0] = strtok(alt_speller, " ");
2163 while ((ptr = strtok(NULL, " ")) != NULL) {
2164 arglen++;
2165 spellargs = (char **)nrealloc(spellargs, arglen *
2166 sizeof(char *));
2167 spellargs[arglen - 3] = ptr;
2168 }
2169 spellargs[arglen - 1] = NULL;
2170 }
2171 spellargs[arglen - 2] = tempfile_name;
2172
2173 /* Start a new process for the alternate speller. */
2174 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey2e2112c2005-11-29 05:39:31 +00002175 /* Start alternate spell program; we are using $PATH. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002176 execvp(spellargs[0], spellargs);
2177
2178 /* Should not be reached, if alternate speller is found!!! */
2179 exit(1);
2180 }
2181
2182 /* If we couldn't fork, get out. */
2183 if (pid_spell < 0)
2184 return _("Could not fork");
2185
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002186#ifndef NANO_TINY
David Lawrence Ramseyb18482e2005-07-26 00:06:34 +00002187 /* Don't handle a pending SIGWINCH until the alternate spell checker
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002188 * is finished and we've loaded the spell-checked file back in. */
David Lawrence Ramseyb18482e2005-07-26 00:06:34 +00002189 allow_pending_sigwinch(FALSE);
2190#endif
2191
2192 /* Wait for the alternate spell checker to finish. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002193 wait(&alt_spell_status);
2194
David Lawrence Ramsey84fdb902005-08-14 20:08:49 +00002195 /* Reenter curses mode. */
2196 doupdate();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002197
2198 /* Restore the terminal to its previous state. */
2199 terminal_init();
2200
2201 /* Turn the cursor back on for sure. */
2202 curs_set(1);
2203
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002204 /* The screen might have been resized. If it has, reinitialize all
2205 * the windows based on the new screen dimensions. */
2206 window_init();
2207
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002208 if (!WIFEXITED(alt_spell_status) ||
2209 WEXITSTATUS(alt_spell_status) != 0) {
2210 char *altspell_error;
2211 char *invoke_error = _("Error invoking \"%s\"");
2212
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002213#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002214 /* Turn the mark back on if it was on before. */
2215 openfile->mark_set = old_mark_set;
2216#endif
2217
2218 altspell_error =
2219 charalloc(strlen(invoke_error) +
2220 strlen(alt_speller) + 1);
2221 sprintf(altspell_error, invoke_error, alt_speller);
2222 return altspell_error;
2223 }
2224
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002225#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002226 if (old_mark_set) {
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002227 /* If the mark is on, partition the filestruct so that it
2228 * contains only the marked text; if the NO_NEWLINES flag isn't
2229 * set, keep track of whether the text will have a magicline
2230 * added when we're done correcting misspelled words; and
2231 * turn the mark off. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002232 mark_order((const filestruct **)&top, &top_x,
2233 (const filestruct **)&bot, &bot_x, &right_side_up);
2234 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002235 if (!ISSET(NO_NEWLINES))
2236 added_magicline = (openfile->filebot->data[0] != '\0');
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002237
2238 /* Get the number of characters in the marked text, and subtract
2239 * it from the saved value of totsize. */
2240 totsize_save -= get_totsize(top, bot);
2241 }
2242#endif
2243
David Lawrence Ramsey9c984e82005-11-08 19:15:58 +00002244 /* Replace the text of the current buffer with the spell-checked
2245 * text. */
2246 replace_buffer(tempfile_name);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002247
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002248#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002249 if (old_mark_set) {
2250 filestruct *top_save = openfile->fileage;
2251
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002252 /* If the mark was on, the NO_NEWLINES flag isn't set, and we
2253 * added a magicline, remove it now. */
2254 if (!ISSET(NO_NEWLINES) && added_magicline)
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002255 remove_magicline();
2256
2257 /* Put the beginning and the end of the mark at the beginning
2258 * and the end of the spell-checked text. */
2259 if (openfile->fileage == openfile->filebot)
2260 bot_x += top_x;
2261 if (right_side_up) {
2262 openfile->mark_begin_x = top_x;
2263 current_x_save = bot_x;
2264 } else {
2265 current_x_save = top_x;
2266 openfile->mark_begin_x = bot_x;
2267 }
2268
2269 /* Unpartition the filestruct so that it contains all the text
2270 * again. Note that we've replaced the marked text originally
2271 * in the partition with the spell-checked marked text in the
2272 * temp file. */
2273 unpartition_filestruct(&filepart);
2274
2275 /* Renumber starting with the beginning line of the old
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002276 * partition. Also add the number of characters in the
2277 * spell-checked marked text to the saved value of totsize, and
2278 * then make that saved value the actual value. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002279 renumber(top_save);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002280 totsize_save += openfile->totsize;
2281 openfile->totsize = totsize_save;
2282
2283 /* Assign mark_begin to the line where the mark began before. */
2284 do_gotopos(mb_lineno_save, openfile->mark_begin_x,
2285 current_y_save, 0);
2286 openfile->mark_begin = openfile->current;
2287
2288 /* Assign mark_begin_x to the location in mark_begin where the
2289 * mark began before, adjusted for any shortening of the
2290 * line. */
2291 openfile->mark_begin_x = openfile->current_x;
2292
2293 /* Turn the mark back on. */
2294 openfile->mark_set = TRUE;
2295 }
2296#endif
2297
2298 /* Go back to the old position, and mark the file as modified. */
2299 do_gotopos(lineno_save, current_x_save, current_y_save, pww_save);
2300 set_modified();
2301
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002302#ifndef NANO_TINY
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002303 /* Handle a pending SIGWINCH again. */
2304 allow_pending_sigwinch(TRUE);
2305#endif
2306
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002307 return NULL;
2308}
2309
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002310/* Spell check the current file. If an alternate spell checker is
2311 * specified, use it. Otherwise, use the internal spell checker. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002312void do_spell(void)
2313{
2314 int i;
2315 FILE *temp_file;
2316 char *temp = safe_tempfile(&temp_file);
2317 const char *spell_msg;
2318
2319 if (temp == NULL) {
David Lawrence Ramseyf0e3ca62006-05-03 13:11:00 +00002320 statusbar(_("Error writing temp file: %s"), strerror(errno));
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002321 return;
2322 }
2323
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002324#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002325 if (openfile->mark_set)
David Lawrence Ramseye014fbd2005-08-29 19:11:26 +00002326 i = write_marked_file(temp, temp_file, TRUE, OVERWRITE);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002327 else
2328#endif
David Lawrence Ramseye014fbd2005-08-29 19:11:26 +00002329 i = write_file(temp, temp_file, TRUE, OVERWRITE, FALSE);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002330
2331 if (i == -1) {
2332 statusbar(_("Error writing temp file: %s"), strerror(errno));
2333 free(temp);
2334 return;
2335 }
2336
2337 spell_msg = (alt_speller != NULL) ? do_alt_speller(temp) :
2338 do_int_speller(temp);
2339 unlink(temp);
2340 free(temp);
2341
2342 /* If the spell-checker printed any error messages onscreen, make
2343 * sure that they're cleared off. */
2344 total_refresh();
2345
2346 if (spell_msg != NULL) {
2347 if (errno == 0)
2348 /* Don't display an error message of "Success". */
2349 statusbar(_("Spell checking failed: %s"), spell_msg);
2350 else
2351 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
2352 strerror(errno));
2353 } else
2354 statusbar(_("Finished checking spelling"));
2355}
2356#endif /* !DISABLE_SPELLER */
2357
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002358#ifndef NANO_TINY
David Lawrence Ramseyd7f0fe92005-08-10 22:51:49 +00002359/* Our own version of "wc". Note that its character counts are in
2360 * multibyte characters instead of single-byte characters. */
David Lawrence Ramsey8e942342005-07-25 04:21:46 +00002361void do_wordlinechar_count(void)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002362{
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002363 size_t words = 0, chars = 0;
2364 ssize_t lines = 0;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002365 size_t current_x_save = openfile->current_x;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002366 size_t pww_save = openfile->placewewant;
2367 filestruct *current_save = openfile->current;
2368 bool old_mark_set = openfile->mark_set;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002369 filestruct *top, *bot;
2370 size_t top_x, bot_x;
2371
2372 if (old_mark_set) {
2373 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +00002374 * contains only the marked text, and turn the mark off. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002375 mark_order((const filestruct **)&top, &top_x,
2376 (const filestruct **)&bot, &bot_x, NULL);
2377 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002378 openfile->mark_set = FALSE;
2379 }
2380
2381 /* Start at the top of the file. */
2382 openfile->current = openfile->fileage;
2383 openfile->current_x = 0;
2384 openfile->placewewant = 0;
2385
2386 /* Keep moving to the next word (counting punctuation characters as
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002387 * part of a word, as "wc -w" does), without updating the screen,
2388 * until we reach the end of the file, incrementing the total word
2389 * count whenever we're on a word just before moving. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002390 while (openfile->current != openfile->filebot ||
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +00002391 openfile->current->data[openfile->current_x] != '\0') {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002392 if (do_next_word(TRUE, FALSE))
2393 words++;
2394 }
2395
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002396 /* Get the total line and character counts, as "wc -l" and "wc -c"
2397 * do, but get the latter in multibyte characters. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002398 if (old_mark_set) {
David Lawrence Ramsey78a81b22005-07-25 18:59:24 +00002399 lines = openfile->filebot->lineno -
2400 openfile->fileage->lineno + 1;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002401 chars = get_totsize(openfile->fileage, openfile->filebot);
2402
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002403 /* Unpartition the filestruct so that it contains all the text
2404 * again, and turn the mark back on. */
2405 unpartition_filestruct(&filepart);
2406 openfile->mark_set = TRUE;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002407 } else {
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002408 lines = openfile->filebot->lineno;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002409 chars = openfile->totsize;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002410 }
2411
2412 /* Restore where we were. */
2413 openfile->current = current_save;
2414 openfile->current_x = current_x_save;
2415 openfile->placewewant = pww_save;
2416
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002417 /* Display the total word, line, and character counts on the
2418 * statusbar. */
David Lawrence Ramsey7b71f572005-10-06 20:46:11 +00002419 statusbar(_("%sWords: %lu Lines: %ld Chars: %lu"), old_mark_set ?
David Lawrence Ramsey815fb0a2005-08-05 19:38:11 +00002420 _("In Selection: ") : "", (unsigned long)words, (long)lines,
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002421 (unsigned long)chars);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002422}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002423#endif /* !NANO_TINY */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002424
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002425/* Get verbatim input. */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002426void do_verbatim_input(void)
2427{
2428 int *kbinput;
2429 size_t kbinput_len, i;
2430 char *output;
2431
2432 statusbar(_("Verbatim Input"));
2433
2434 /* If constant cursor position display is on, make sure the current
2435 * cursor position will be properly displayed on the statusbar. */
2436 if (ISSET(CONST_UPDATE))
2437 do_cursorpos(TRUE);
2438
2439 /* Read in all the verbatim characters. */
2440 kbinput = get_verbatim_kbinput(edit, &kbinput_len);
2441
2442 /* Display all the verbatim characters at once, not filtering out
2443 * control characters. */
2444 output = charalloc(kbinput_len + 1);
2445
2446 for (i = 0; i < kbinput_len; i++)
2447 output[i] = (char)kbinput[i];
2448 output[i] = '\0';
2449
2450 do_output(output, kbinput_len, TRUE);
2451
2452 free(output);
2453}