blob: f1ccb397b0607ddeb3de6fcf7aa05caa94ded430 [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--;
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000127
David Lawrence Ramseya0168ca2005-11-05 17:35:44 +0000128 /* If the NO_NEWLINES flag isn't set, and text has been added to
129 * the magicline as a result of deleting at the end of the line
David Lawrence Ramsey0f6236f2005-11-09 00:08:29 +0000130 * before filebot, add a new magicline. */
David Lawrence Ramseya0168ca2005-11-05 17:35:44 +0000131 if (!ISSET(NO_NEWLINES) && openfile->current ==
132 openfile->filebot && openfile->current->data[0] != '\0')
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000133 new_magicline();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000134 } else
135 return;
136
David Lawrence Ramsey0f6236f2005-11-09 00:08:29 +0000137 set_modified();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000138
139#ifdef ENABLE_COLOR
140 /* If color syntaxes are available and turned on, we need to call
141 * edit_refresh(). */
142 if (openfile->colorstrings != NULL && !ISSET(NO_COLOR_SYNTAX))
143 do_refresh = TRUE;
144#endif
145
146 if (do_refresh)
147 edit_refresh();
148 else
149 update_line(openfile->current, openfile->current_x);
150}
151
David Lawrence Ramsey5b7b3e32005-12-31 21:22:54 +0000152/* Backspace over one character. That is, move the cursor left one
153 * character, and then delete the character there. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000154void do_backspace(void)
155{
156 if (openfile->current != openfile->fileage ||
157 openfile->current_x > 0) {
David Lawrence Ramsey1c3bfa92005-09-13 04:53:44 +0000158 do_left();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000159 do_delete();
160 }
161}
162
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000163/* Insert a tab. If the TABS_TO_SPACES flag is set, insert the number
164 * of spaces that a tab would normally take up. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000165void do_tab(void)
166{
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000167#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000168 if (ISSET(TABS_TO_SPACES)) {
169 char *output;
David Lawrence Ramsey90b07fc2005-10-07 15:57:48 +0000170 size_t output_len = 0, new_pww = xplustabs();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000171
172 do {
173 new_pww++;
174 output_len++;
175 } while (new_pww % tabsize != 0);
176
177 output = charalloc(output_len + 1);
178
179 charset(output, ' ', output_len);
180 output[output_len] = '\0';
181
182 do_output(output, output_len, TRUE);
183
184 free(output);
185 } else {
186#endif
187 do_output("\t", 1, TRUE);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000188#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000189 }
190#endif
191}
192
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000193#ifndef NANO_TINY
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000194/* Indent or unindent all lines covered by the mark len columns,
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000195 * depending on whether len is positive or negative. If the
196 * TABS_TO_SPACES flag is set, indent/unindent by len spaces.
197 * Otherwise, indent/unindent by (len / tabsize) tabs and (len %
198 * tabsize) spaces. */
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000199void do_indent_marked(ssize_t cols)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000200{
201 bool indent_changed = FALSE;
202 /* Whether any indenting or unindenting was done. */
203 bool unindent = FALSE;
204 /* Whether we're unindenting text. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000205 char *line_indent = NULL;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000206 /* The text added to each line in order to indent it. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000207 size_t line_indent_len = 0;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000208 /* The length of the text added to each line in order to indent
209 * it. */
210 filestruct *top, *bot, *f;
211 size_t top_x, bot_x;
212
213 assert(openfile->current != NULL && openfile->current->data != NULL);
214
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000215 /* If the mark isn't on, indicate it on the statusbar and get
216 * out. */
217 if (!openfile->mark_set) {
218 statusbar(_("No lines selected, nothing to do!"));
219 return;
220 }
221
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000222 /* If cols is zero, get out. */
223 if (cols == 0)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000224 return;
225
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000226 /* If cols is negative, make it positive and set unindent to
227 * TRUE. */
228 if (cols < 0) {
229 cols = -cols;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000230 unindent = TRUE;
231 /* Otherwise, we're indenting, in which case the file will always be
232 * modified, so set indent_changed to TRUE. */
233 } else
234 indent_changed = TRUE;
235
236 /* Get the coordinates of the marked text. */
237 mark_order((const filestruct **)&top, &top_x,
238 (const filestruct **)&bot, &bot_x, NULL);
239
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000240 if (!unindent) {
241 /* Set up the text we'll be using as indentation. */
242 line_indent = charalloc(cols + 1);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000243
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000244 if (ISSET(TABS_TO_SPACES)) {
245 /* Set the indentation to cols spaces. */
246 charset(line_indent, ' ', cols);
247 line_indent_len = cols;
248 } else {
249 /* Set the indentation to (cols / tabsize) tabs and (cols %
250 * tabsize) spaces. */
251 size_t num_tabs = cols / tabsize;
252 size_t num_spaces = cols % tabsize;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000253
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000254 charset(line_indent, '\t', num_tabs);
255 charset(line_indent + num_tabs, ' ', num_spaces);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000256
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000257 line_indent_len = num_tabs + num_spaces;
258 }
259
260 line_indent[line_indent_len] = '\0';
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000261 }
262
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000263 /* Go through each line of the marked text. */
264 for (f = top; f != bot->next; f = f->next) {
265 size_t line_len = strlen(f->data);
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000266 size_t indent_len = indent_length(f->data);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000267
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000268 if (!unindent) {
269 /* If we're indenting, add the characters in line_indent to
270 * the beginning of the non-whitespace text of this line. */
271 f->data = charealloc(f->data, line_len +
272 line_indent_len + 1);
273 charmove(&f->data[indent_len + line_indent_len],
274 &f->data[indent_len], line_len - indent_len + 1);
275 strncpy(f->data + indent_len, line_indent, line_indent_len);
276 openfile->totsize += line_indent_len;
277
278 /* Keep track of the change in the current line. */
279 if (f == openfile->mark_begin && openfile->mark_begin_x >=
280 indent_len)
281 openfile->mark_begin_x += line_indent_len;
282
283 if (f == openfile->current && openfile->current_x >=
284 indent_len)
285 openfile->current_x += line_indent_len;
286
287 /* If the NO_NEWLINES flag isn't set, and this is the
288 * magicline, add a new magicline. */
289 if (!ISSET(NO_NEWLINES) && f == openfile->filebot)
290 new_magicline();
291 } else {
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000292 size_t indent_col = strnlenpt(f->data, indent_len);
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000293 /* The length in columns of the indentation on this
294 * line. */
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000295
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000296 if (cols <= indent_col) {
297 size_t indent_new = actual_x(f->data, indent_col -
298 cols);
David Lawrence Ramsey5bb77272006-05-06 14:37:33 +0000299 /* The length of the indentation remaining on
300 * this line after we unindent. */
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000301 size_t indent_shift = indent_len - indent_new;
David Lawrence Ramsey5bb77272006-05-06 14:37:33 +0000302 /* The change in the indentation on this line
303 * after we unindent. */
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000304
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000305 /* If we're unindenting, and there's at least cols
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000306 * columns' worth of indentation at the beginning of the
307 * non-whitespace text of this line, remove it. */
308 charmove(&f->data[indent_new], &f->data[indent_len],
309 line_len - indent_shift - indent_new + 1);
310 null_at(&f->data, line_len - indent_shift + 1);
311 openfile->totsize -= indent_shift;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000312
David Lawrence Ramsey2e8fac62006-04-29 15:44:58 +0000313 /* Keep track of the change in the current line. */
David Lawrence Ramsey2e8fac62006-04-29 15:44:58 +0000314 if (f == openfile->mark_begin &&
David Lawrence Ramseyeb4f90e2006-05-05 14:22:42 +0000315 openfile->mark_begin_x > indent_new) {
316 if (openfile->mark_begin_x <= indent_len)
317 openfile->mark_begin_x = indent_new;
318 else
319 openfile->mark_begin_x -= indent_shift;
320 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000321
David Lawrence Ramseyac37b042006-05-03 12:59:05 +0000322 if (f == openfile->current && openfile->current_x >
David Lawrence Ramseyeb4f90e2006-05-05 14:22:42 +0000323 indent_new) {
324 if (openfile->current_x <= indent_len)
325 openfile->current_x = indent_new;
326 else
327 openfile->current_x -= indent_shift;
328 }
David Lawrence Ramsey7194a612006-04-29 16:11:21 +0000329
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000330 /* We've unindented, so set indent_changed to TRUE. */
331 if (!indent_changed)
332 indent_changed = TRUE;
333 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000334 }
335 }
336
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000337 if (!unindent)
David Lawrence Ramsey25456862006-05-05 15:43:52 +0000338 /* Clean up. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000339 free(line_indent);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000340
341 if (indent_changed) {
342 /* Mark the file as modified. */
343 set_modified();
344
345 /* Update the screen. */
346 edit_refresh();
347 }
348}
349
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000350/* Indent all lines covered by the mark tabsize columns. */
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000351void do_indent_marked_void(void)
352{
353 do_indent_marked(tabsize);
354}
355
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000356/* Unindent all lines covered by the mark tabsize columns. */
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000357void do_unindent_marked_void(void)
358{
359 do_indent_marked(-tabsize);
360}
361#endif /* !NANO_TINY */
362
David Lawrence Ramseyb0e04c02005-12-08 07:24:54 +0000363/* Someone hits Enter *gasp!* */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000364void do_enter(void)
365{
366 filestruct *newnode = make_new_node(openfile->current);
367 size_t extra = 0;
368
369 assert(openfile->current != NULL && openfile->current->data != NULL);
370
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000371#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000372 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
373 if (ISSET(AUTOINDENT)) {
374 /* If we are breaking the line in the indentation, the new
375 * indentation should have only current_x characters, and
376 * current_x should not change. */
377 extra = indent_length(openfile->current->data);
378 if (extra > openfile->current_x)
379 extra = openfile->current_x;
380 }
381#endif
382 newnode->data = charalloc(strlen(openfile->current->data +
383 openfile->current_x) + extra + 1);
384 strcpy(&newnode->data[extra], openfile->current->data +
385 openfile->current_x);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000386#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000387 if (ISSET(AUTOINDENT)) {
388 strncpy(newnode->data, openfile->current->data, extra);
389 openfile->totsize += mbstrlen(newnode->data);
390 }
391#endif
392 null_at(&openfile->current->data, openfile->current_x);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000393#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000394 if (openfile->mark_set && openfile->current ==
395 openfile->mark_begin && openfile->current_x <
396 openfile->mark_begin_x) {
397 openfile->mark_begin = newnode;
398 openfile->mark_begin_x += extra - openfile->current_x;
399 }
400#endif
401 openfile->current_x = extra;
402
403 if (openfile->current == openfile->filebot)
404 openfile->filebot = newnode;
405 splice_node(openfile->current, newnode,
406 openfile->current->next);
407
408 renumber(openfile->current);
409 openfile->current = newnode;
410
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000411 openfile->totsize++;
412 set_modified();
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +0000413
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000414 openfile->placewewant = xplustabs();
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +0000415
416 edit_refresh();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000417}
418
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000419#ifndef NANO_TINY
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000420/* Send a SIGKILL (unconditional kill) to the forked process in
421 * execute_command(). */
David Lawrence Ramsey8befda62005-12-06 19:39:56 +0000422RETSIGTYPE cancel_command(int signal)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000423{
424 if (kill(pid, SIGKILL) == -1)
425 nperror("kill");
426}
427
David Lawrence Ramsey0ed71712005-11-08 23:09:47 +0000428/* Execute command in a shell. Return TRUE on success. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000429bool execute_command(const char *command)
430{
431 int fd[2];
432 FILE *f;
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000433 char *shellenv;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000434 struct sigaction oldaction, newaction;
435 /* Original and temporary handlers for SIGINT. */
436 bool sig_failed = FALSE;
437 /* Did sigaction() fail without changing the signal handlers? */
438
439 /* Make our pipes. */
440 if (pipe(fd) == -1) {
441 statusbar(_("Could not pipe"));
442 return FALSE;
443 }
444
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000445 /* Check $SHELL for the shell to use. If it isn't set, use
David Lawrence Ramsey1932dfb2005-11-29 05:52:49 +0000446 * /bin/sh. Note that $SHELL should contain only a path, with no
447 * arguments. */
David Lawrence Ramseyeae85712005-11-29 05:48:06 +0000448 shellenv = getenv("SHELL");
449 if (shellenv == NULL)
450 shellenv = "/bin/sh";
451
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000452 /* Fork a child. */
453 if ((pid = fork()) == 0) {
454 close(fd[0]);
455 dup2(fd[1], fileno(stdout));
456 dup2(fd[1], fileno(stderr));
457
458 /* If execl() returns at all, there was an error. */
David Lawrence Ramsey5da68ee2005-11-29 05:21:06 +0000459 execl(shellenv, tail(shellenv), "-c", command, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000460 exit(0);
461 }
462
David Lawrence Ramseyc838a4c2006-04-26 18:33:50 +0000463 /* Continue as parent. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000464 close(fd[1]);
465
466 if (pid == -1) {
467 close(fd[0]);
468 statusbar(_("Could not fork"));
469 return FALSE;
470 }
471
472 /* Before we start reading the forked command's output, we set
473 * things up so that Ctrl-C will cancel the new process. */
474
475 /* Enable interpretation of the special control keys so that we get
476 * SIGINT when Ctrl-C is pressed. */
477 enable_signals();
478
479 if (sigaction(SIGINT, NULL, &newaction) == -1) {
480 sig_failed = TRUE;
481 nperror("sigaction");
482 } else {
483 newaction.sa_handler = cancel_command;
484 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
485 sig_failed = TRUE;
486 nperror("sigaction");
487 }
488 }
489
490 /* Note that now oldaction is the previous SIGINT signal handler,
491 * to be restored later. */
492
493 f = fdopen(fd[0], "rb");
494 if (f == NULL)
495 nperror("fdopen");
496
497 read_file(f, "stdin");
498
499 /* If multibuffer mode is on, we could be here in view mode. If so,
500 * don't set the modification flag. */
501 if (!ISSET(VIEW_MODE))
502 set_modified();
503
504 if (wait(NULL) == -1)
505 nperror("wait");
506
507 if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
508 nperror("sigaction");
509
510 /* Disable interpretation of the special control keys so that we can
511 * use Ctrl-C for other things. */
512 disable_signals();
513
514 return TRUE;
515}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000516#endif /* !NANO_TINY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000517
518#ifndef DISABLE_WRAPPING
David Lawrence Ramseyef0d5a72006-05-22 02:08:49 +0000519/* Unset the prepend_wrap flag. We need to do this as soon as we do
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000520 * something other than type text. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000521void wrap_reset(void)
522{
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000523 prepend_wrap = FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000524}
525
526/* We wrap the given line. Precondition: we assume the cursor has been
David Lawrence Ramsey139fa652006-05-22 01:26:24 +0000527 * moved forward since the last typed character. Return TRUE if we
528 * wrapped, and FALSE otherwise. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000529bool do_wrap(filestruct *line)
530{
531 size_t line_len;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000532 /* The length of the line we wrap. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000533 ssize_t wrap_loc;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000534 /* The index of line->data where we wrap. */
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000535#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000536 const char *indent_string = NULL;
537 /* Indentation to prepend to the new line. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000538 size_t indent_len = 0;
539 /* The length of indent_string. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000540#endif
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000541 const char *after_break;
542 /* The text after the wrap point. */
543 size_t after_break_len;
544 /* The length of after_break. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000545 bool prepending = FALSE;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000546 /* Do we prepend to the next line? */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000547 const char *next_line = NULL;
548 /* The next line, minus indentation. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +0000549 size_t next_line_len = 0;
550 /* The length of next_line. */
551 char *new_line = NULL;
552 /* The line we create. */
553 size_t new_line_len = 0;
554 /* The eventual length of new_line. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000555
556 /* There are three steps. First, we decide where to wrap. Then, we
557 * create the new wrap line. Finally, we clean up. */
558
559 /* Step 1, finding where to wrap. We are going to add a new line
560 * after a blank character. In this step, we call break_line() to
561 * get the location of the last blank we can break the line at, and
562 * and set wrap_loc to the location of the character after it, so
563 * that the blank is preserved at the end of the line.
564 *
565 * If there is no legal wrap point, or we reach the last character
566 * of the line while trying to find one, we should return without
567 * wrapping. Note that if autoindent is turned on, we don't break
568 * at the end of it! */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000569 assert(line != NULL && line->data != NULL);
570
571 /* Save the length of the line. */
572 line_len = strlen(line->data);
573
574 /* Find the last blank where we can break the line. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000575 wrap_loc = break_line(line->data, fill
576#ifndef DISABLE_HELP
577 , FALSE
578#endif
579 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000580
581 /* If we couldn't break the line, or we've reached the end of it, we
582 * don't wrap. */
583 if (wrap_loc == -1 || line->data[wrap_loc] == '\0')
584 return FALSE;
585
586 /* Otherwise, move forward to the character just after the blank. */
587 wrap_loc += move_mbright(line->data + wrap_loc, 0);
588
589 /* If we've reached the end of the line, we don't wrap. */
590 if (line->data[wrap_loc] == '\0')
591 return FALSE;
592
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000593#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000594 /* If autoindent is turned on, and we're on the character just after
595 * the indentation, we don't wrap. */
596 if (ISSET(AUTOINDENT)) {
597 /* Get the indentation of this line. */
598 indent_string = line->data;
599 indent_len = indent_length(indent_string);
600
601 if (wrap_loc == indent_len)
602 return FALSE;
603 }
604#endif
605
606 /* Step 2, making the new wrap line. It will consist of indentation
607 * followed by the text after the wrap point, optionally followed by
608 * a space (if the text after the wrap point doesn't end in a blank)
609 * and the text of the next line, if they can fit without
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000610 * wrapping, the next line exists, and the prepend_wrap flag is
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000611 * set. */
612
613 /* after_break is the text that will be wrapped to the next line. */
614 after_break = line->data + wrap_loc;
615 after_break_len = line_len - wrap_loc;
616
617 assert(strlen(after_break) == after_break_len);
618
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000619 /* We prepend the wrapped text to the next line, if the prepend_wrap
620 * flag is set, there is a next line, and prepending would not make
621 * the line too long. */
622 if (prepend_wrap && line != openfile->filebot) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000623 const char *end = after_break + move_mbleft(after_break,
624 after_break_len);
625
626 /* If after_break doesn't end in a blank, make sure it ends in a
627 * space. */
628 if (!is_blank_mbchar(end)) {
629 line_len++;
630 line->data = charealloc(line->data, line_len + 1);
631 line->data[line_len - 1] = ' ';
632 line->data[line_len] = '\0';
633 after_break = line->data + wrap_loc;
634 after_break_len++;
635 openfile->totsize++;
636 }
637
638 next_line = line->next->data;
639 next_line_len = strlen(next_line);
640
641 if (after_break_len + next_line_len <= fill) {
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000642 prepending = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000643 new_line_len += next_line_len;
644 }
645 }
646
647 /* new_line_len is now the length of the text that will be wrapped
648 * to the next line, plus (if we're prepending to it) the length of
649 * the text of the next line. */
650 new_line_len += after_break_len;
651
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000652#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000653 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000654 if (prepending) {
655 /* If we're prepending, the indentation will come from the
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000656 * next line. */
657 indent_string = next_line;
658 indent_len = indent_length(indent_string);
659 next_line += indent_len;
660 } else {
661 /* Otherwise, it will come from this line, in which case
662 * we should increase new_line_len to make room for it. */
663 new_line_len += indent_len;
664 openfile->totsize += mbstrnlen(indent_string, indent_len);
665 }
666 }
667#endif
668
669 /* Now we allocate the new line and copy the text into it. */
670 new_line = charalloc(new_line_len + 1);
671 new_line[0] = '\0';
672
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000673#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000674 if (ISSET(AUTOINDENT)) {
675 /* Copy the indentation. */
676 strncpy(new_line, indent_string, indent_len);
677 new_line[indent_len] = '\0';
678 new_line_len += indent_len;
679 }
680#endif
681
682 /* Copy all the text after the wrap point of the current line. */
683 strcat(new_line, after_break);
684
685 /* Break the current line at the wrap point. */
686 null_at(&line->data, wrap_loc);
687
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000688 if (prepending) {
689 /* If we're prepending, copy the text from the next line, minus
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000690 * the indentation that we already copied above. */
691 strcat(new_line, next_line);
692
693 free(line->next->data);
694 line->next->data = new_line;
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000695
696 /* If the NO_NEWLINES flag isn't set, and text has been added to
697 * the magicline, make a new magicline. */
698 if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0')
699 new_magicline();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000700 } else {
701 /* Otherwise, make a new line and copy the text after where we
702 * broke this line to the beginning of the new line. */
703 splice_node(openfile->current, make_new_node(openfile->current),
704 openfile->current->next);
705
David Lawrence Ramsey219a8142005-11-22 22:08:01 +0000706 /* If the current line is the last line of the file, move the
707 * last line of the file down to the next line. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000708 if (openfile->filebot == openfile->current)
709 openfile->filebot = openfile->current->next;
710
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000711 openfile->current->next->data = new_line;
712
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000713 openfile->totsize++;
714 }
715
716 /* Step 3, clean up. Reposition the cursor and mark, and do some
717 * other sundry things. */
718
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000719 /* Set the prepend_wrap flag, so that later wraps of this line will
720 * be prepended to the next line. */
721 prepend_wrap = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000722
David Lawrence Ramsey2829aae2006-05-22 01:24:09 +0000723 /* Each line knows its number. We recalculate these if we inserted
724 * a new line. */
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000725 if (!prepending)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000726 renumber(line);
727
728 /* If the cursor was after the break point, we must move it. We
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000729 * also clear the prepend_wrap flag in this case. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000730 if (openfile->current_x > wrap_loc) {
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +0000731 prepend_wrap = FALSE;
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000732
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000733 openfile->current = openfile->current->next;
734 openfile->current_x -= wrap_loc
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000735#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000736 - indent_len
737#endif
738 ;
739 openfile->placewewant = xplustabs();
740 }
741
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000742#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000743 /* If the mark was on this line after the wrap point, we move it
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000744 * down. If it was on the next line and we prepended to that line,
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000745 * we move it right. */
746 if (openfile->mark_set) {
747 if (openfile->mark_begin == line && openfile->mark_begin_x >
748 wrap_loc) {
749 openfile->mark_begin = line->next;
750 openfile->mark_begin_x -= wrap_loc - indent_len + 1;
David Lawrence Ramsey615f4c72005-11-22 21:48:24 +0000751 } else if (prepending && openfile->mark_begin == line->next)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000752 openfile->mark_begin_x += after_break_len;
753 }
754#endif
755
756 return TRUE;
757}
758#endif /* !DISABLE_WRAPPING */
759
David Lawrence Ramseyc7c04bb2005-11-29 21:30:00 +0000760#if !defined(DISABLE_HELP) || !defined(DISABLE_WRAPJUSTIFY)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000761/* We are trying to break a chunk off line. We find the last blank such
David Lawrence Ramseycd9a5f02005-09-20 06:12:54 +0000762 * that the display length to there is at most (goal + 1). If there is
763 * no such blank, then we find the first blank. We then take the last
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000764 * blank in that group of blanks. The terminating '\0' counts as a
765 * blank, as does a '\n' if newline is TRUE. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000766ssize_t break_line(const char *line, ssize_t goal
767#ifndef DISABLE_HELP
768 , bool newline
769#endif
770 )
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000771{
772 ssize_t blank_loc = -1;
773 /* Current tentative return value. Index of the last blank we
774 * found with short enough display width. */
775 ssize_t cur_loc = 0;
776 /* Current index in line. */
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +0000777 size_t cur_pos = 0;
778 /* Current column position in line. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000779 int line_len;
780
781 assert(line != NULL);
782
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +0000783 while (*line != '\0' && goal >= cur_pos) {
784 line_len = parse_mbchar(line, NULL, &cur_pos);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000785
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000786 if (is_blank_mbchar(line)
787#ifndef DISABLE_HELP
788 || (newline && *line == '\n')
789#endif
790 ) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000791 blank_loc = cur_loc;
792
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000793#ifndef DISABLE_HELP
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000794 if (newline && *line == '\n')
795 break;
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000796#endif
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000797 }
798
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000799 line += line_len;
800 cur_loc += line_len;
801 }
802
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +0000803 if (goal >= cur_pos)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000804 /* In fact, the whole line displays shorter than goal. */
805 return cur_loc;
806
807 if (blank_loc == -1) {
808 /* No blank was found that was short enough. */
809 bool found_blank = FALSE;
David Lawrence Ramsey5ab12ca2005-09-20 17:52:52 +0000810 ssize_t found_blank_loc = 0;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000811
812 while (*line != '\0') {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000813 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000814
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000815 if (is_blank_mbchar(line)
816#ifndef DISABLE_HELP
817 || (newline && *line == '\n')
818#endif
819 ) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000820 if (!found_blank)
821 found_blank = TRUE;
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +0000822 found_blank_loc = cur_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000823 } else if (found_blank)
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +0000824 return found_blank_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000825
826 line += line_len;
827 cur_loc += line_len;
828 }
829
830 return -1;
831 }
832
833 /* Move to the last blank after blank_loc, if there is one. */
834 line -= cur_loc;
835 line += blank_loc;
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000836 line_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000837 line += line_len;
838
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +0000839 while (*line != '\0' && (is_blank_mbchar(line)
840#ifndef DISABLE_HELP
841 || (newline && *line == '\n')
842#endif
843 )) {
David Lawrence Ramseycd243f52006-05-19 23:27:16 +0000844#ifndef DISABLE_HELP
845 if (newline && *line == '\n')
846 break;
847#endif
848
David Lawrence Ramsey39bd1b32006-05-20 13:11:56 +0000849 line_len = parse_mbchar(line, NULL, NULL);
850
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000851 line += line_len;
852 blank_loc += line_len;
853 }
854
855 return blank_loc;
856}
David Lawrence Ramseyc7c04bb2005-11-29 21:30:00 +0000857#endif /* !DISABLE_HELP || !DISABLE_WRAPJUSTIFY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000858
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000859#if !defined(NANO_TINY) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000860/* The "indentation" of a line is the whitespace between the quote part
861 * and the non-whitespace of the line. */
862size_t indent_length(const char *line)
863{
864 size_t len = 0;
865 char *blank_mb;
866 int blank_mb_len;
867
868 assert(line != NULL);
869
870 blank_mb = charalloc(mb_cur_max());
871
872 while (*line != '\0') {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000873 blank_mb_len = parse_mbchar(line, blank_mb, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000874
875 if (!is_blank_mbchar(blank_mb))
876 break;
877
878 line += blank_mb_len;
879 len += blank_mb_len;
880 }
881
882 free(blank_mb);
883
884 return len;
885}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000886#endif /* !NANO_TINY || !DISABLE_JUSTIFY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000887
888#ifndef DISABLE_JUSTIFY
889/* justify_format() replaces blanks with spaces and multiple spaces by 1
890 * (except it maintains up to 2 after a character in punct optionally
891 * followed by a character in brackets, and removes all from the end).
892 *
893 * justify_format() might make paragraph->data shorter, and change the
894 * actual pointer with null_at().
895 *
896 * justify_format() will not look at the first skip characters of
897 * paragraph. skip should be at most strlen(paragraph->data). The
898 * character at paragraph[skip + 1] must not be blank. */
899void justify_format(filestruct *paragraph, size_t skip)
900{
901 char *end, *new_end, *new_paragraph_data;
902 size_t shift = 0;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000903#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000904 size_t mark_shift = 0;
905#endif
906
907 /* These four asserts are assumptions about the input data. */
908 assert(paragraph != NULL);
909 assert(paragraph->data != NULL);
910 assert(skip < strlen(paragraph->data));
911 assert(!is_blank_mbchar(paragraph->data + skip));
912
913 end = paragraph->data + skip;
914 new_paragraph_data = charalloc(strlen(paragraph->data) + 1);
915 strncpy(new_paragraph_data, paragraph->data, skip);
916 new_end = new_paragraph_data + skip;
917
918 while (*end != '\0') {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000919 int end_len;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000920
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000921 /* If this character is blank, change it to a space if
922 * necessary, and skip over all blanks after it. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000923 if (is_blank_mbchar(end)) {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000924 end_len = parse_mbchar(end, NULL, NULL);
925
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000926 *new_end = ' ';
927 new_end++;
928 end += end_len;
929
930 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000931 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000932
933 end += end_len;
934 shift += end_len;
935
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000936#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000937 /* Keep track of the change in the current line. */
938 if (openfile->mark_set && openfile->mark_begin ==
939 paragraph && openfile->mark_begin_x >= end -
940 paragraph->data)
941 mark_shift += end_len;
942#endif
943 }
944 /* If this character is punctuation optionally followed by a
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000945 * bracket and then followed by blanks, change no more than two
946 * of the blanks to spaces if necessary, and skip over all
947 * blanks after them. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000948 } else if (mbstrchr(punct, end) != NULL) {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +0000949 end_len = parse_mbchar(end, NULL, NULL);
950
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000951 while (end_len > 0) {
952 *new_end = *end;
953 new_end++;
954 end++;
955 end_len--;
956 }
957
958 if (*end != '\0' && mbstrchr(brackets, end) != NULL) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000959 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000960
961 while (end_len > 0) {
962 *new_end = *end;
963 new_end++;
964 end++;
965 end_len--;
966 }
967 }
968
969 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000970 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000971
972 *new_end = ' ';
973 new_end++;
974 end += end_len;
975 }
976
977 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000978 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000979
980 *new_end = ' ';
981 new_end++;
982 end += end_len;
983 }
984
985 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +0000986 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000987
988 end += end_len;
989 shift += end_len;
990
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000991#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000992 /* Keep track of the change in the current line. */
993 if (openfile->mark_set && openfile->mark_begin ==
994 paragraph && openfile->mark_begin_x >= end -
995 paragraph->data)
996 mark_shift += end_len;
997#endif
998 }
999 /* If this character is neither blank nor punctuation, leave it
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001000 * unchanged. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001001 } else {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001002 end_len = parse_mbchar(end, NULL, NULL);
1003
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001004 while (end_len > 0) {
1005 *new_end = *end;
1006 new_end++;
1007 end++;
1008 end_len--;
1009 }
1010 }
1011 }
1012
1013 assert(*end == '\0');
1014
1015 *new_end = *end;
1016
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001017 /* If there are spaces at the end of the line, remove them. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001018 while (new_end > new_paragraph_data + skip &&
1019 *(new_end - 1) == ' ') {
1020 new_end--;
1021 shift++;
1022 }
1023
1024 if (shift > 0) {
1025 openfile->totsize -= shift;
1026 null_at(&new_paragraph_data, new_end - new_paragraph_data);
1027 free(paragraph->data);
1028 paragraph->data = new_paragraph_data;
1029
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001030#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001031 /* Adjust the mark coordinates to compensate for the change in
1032 * the current line. */
1033 if (openfile->mark_set && openfile->mark_begin == paragraph) {
1034 openfile->mark_begin_x -= mark_shift;
1035 if (openfile->mark_begin_x > new_end - new_paragraph_data)
1036 openfile->mark_begin_x = new_end - new_paragraph_data;
1037 }
1038#endif
1039 } else
1040 free(new_paragraph_data);
1041}
1042
1043/* The "quote part" of a line is the largest initial substring matching
1044 * the quote string. This function returns the length of the quote part
1045 * of the given line.
1046 *
1047 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1048 * quotestr. */
1049size_t quote_length(const char *line)
1050{
1051#ifdef HAVE_REGEX_H
1052 regmatch_t matches;
1053 int rc = regexec(&quotereg, line, 1, &matches, 0);
1054
1055 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
1056 return 0;
1057 /* matches.rm_so should be 0, since the quote string should start
1058 * with the caret ^. */
1059 return matches.rm_eo;
1060#else /* !HAVE_REGEX_H */
1061 size_t qdepth = 0;
1062
1063 /* Compute quote depth level. */
1064 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
1065 qdepth += quotelen;
1066 return qdepth;
1067#endif /* !HAVE_REGEX_H */
1068}
1069
1070/* a_line and b_line are lines of text. The quotation part of a_line is
1071 * the first a_quote characters. Check that the quotation part of
1072 * b_line is the same. */
1073bool quotes_match(const char *a_line, size_t a_quote, const char
1074 *b_line)
1075{
1076 /* Here is the assumption about a_quote. */
1077 assert(a_quote == quote_length(a_line));
1078
1079 return (a_quote == quote_length(b_line) &&
1080 strncmp(a_line, b_line, a_quote) == 0);
1081}
1082
1083/* We assume a_line and b_line have no quote part. Then, we return
1084 * whether b_line could follow a_line in a paragraph. */
1085bool indents_match(const char *a_line, size_t a_indent, const char
1086 *b_line, size_t b_indent)
1087{
1088 assert(a_indent == indent_length(a_line));
1089 assert(b_indent == indent_length(b_line));
1090
1091 return (b_indent <= a_indent &&
1092 strncmp(a_line, b_line, b_indent) == 0);
1093}
1094
1095/* Is foo the beginning of a paragraph?
1096 *
1097 * A line of text consists of a "quote part", followed by an
1098 * "indentation part", followed by text. The functions quote_length()
1099 * and indent_length() calculate these parts.
1100 *
1101 * A line is "part of a paragraph" if it has a part not in the quote
1102 * part or the indentation.
1103 *
1104 * A line is "the beginning of a paragraph" if it is part of a
1105 * paragraph and
1106 * 1) it is the top line of the file, or
1107 * 2) the line above it is not part of a paragraph, or
1108 * 3) the line above it does not have precisely the same quote
1109 * part, or
1110 * 4) the indentation of this line is not an initial substring of
1111 * the indentation of the previous line, or
1112 * 5) this line has no quote part and some indentation, and
1113 * autoindent isn't turned on.
1114 * The reason for number 5) is that if autoindent isn't turned on,
1115 * then an indented line is expected to start a paragraph, as in
1116 * books. Thus, nano can justify an indented paragraph only if
1117 * autoindent is turned on. */
1118bool begpar(const filestruct *const foo)
1119{
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +00001120 size_t quote_len, indent_len, temp_id_len;
1121
1122 if (foo == NULL)
1123 return FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001124
1125 /* Case 1). */
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +00001126 if (foo == openfile->fileage)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001127 return TRUE;
1128
1129 quote_len = quote_length(foo->data);
1130 indent_len = indent_length(foo->data + quote_len);
1131
1132 /* Not part of a paragraph. */
1133 if (foo->data[quote_len + indent_len] == '\0')
1134 return FALSE;
1135
1136 /* Case 3). */
1137 if (!quotes_match(foo->data, quote_len, foo->prev->data))
1138 return TRUE;
1139
1140 temp_id_len = indent_length(foo->prev->data + quote_len);
1141
1142 /* Case 2) or 5) or 4). */
1143 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
1144 (quote_len == 0 && indent_len > 0
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001145#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001146 && !ISSET(AUTOINDENT)
1147#endif
1148 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
1149 foo->data + quote_len, indent_len))
1150 return TRUE;
1151
1152 return FALSE;
1153}
1154
1155/* Is foo inside a paragraph? */
1156bool inpar(const filestruct *const foo)
1157{
1158 size_t quote_len;
1159
1160 if (foo == NULL)
1161 return FALSE;
1162
1163 quote_len = quote_length(foo->data);
1164
David Lawrence Ramsey21014032005-11-09 20:33:42 +00001165 return (foo->data[quote_len + indent_length(foo->data +
1166 quote_len)] != '\0');
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001167}
1168
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001169/* Move the next par_len lines, starting with first_line, into the
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001170 * justify buffer, leaving copies of those lines in place. Assume that
1171 * par_len is greater than zero, and that there are enough lines after
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001172 * first_line. */
1173void backup_lines(filestruct *first_line, size_t par_len)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001174{
1175 filestruct *top = first_line;
1176 /* The top of the paragraph we're backing up. */
1177 filestruct *bot = first_line;
1178 /* The bottom of the paragraph we're backing up. */
1179 size_t i;
1180 /* Generic loop variable. */
1181 size_t current_x_save = openfile->current_x;
1182 ssize_t fl_lineno_save = first_line->lineno;
1183 ssize_t edittop_lineno_save = openfile->edittop->lineno;
1184 ssize_t current_lineno_save = openfile->current->lineno;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001185#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001186 bool old_mark_set = openfile->mark_set;
1187 ssize_t mb_lineno_save = 0;
1188 size_t mark_begin_x_save = 0;
1189
1190 if (old_mark_set) {
1191 mb_lineno_save = openfile->mark_begin->lineno;
1192 mark_begin_x_save = openfile->mark_begin_x;
1193 }
1194#endif
1195
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001196 /* par_len will be one greater than the number of lines between
1197 * current and filebot if filebot is the last line in the
1198 * paragraph. */
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001199 assert(par_len > 0 && openfile->current->lineno + par_len <=
David Lawrence Ramsey24777c02005-12-01 05:49:08 +00001200 openfile->filebot->lineno + 1);
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00001201
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001202 /* Move bot down par_len lines to the line after the last line of
1203 * the paragraph, if there is one. */
1204 for (i = par_len; i > 0 && bot != openfile->filebot; i--)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001205 bot = bot->next;
1206
1207 /* Move the paragraph from the current buffer's filestruct to the
1208 * justify buffer. */
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001209 move_to_filestruct(&jusbuffer, &jusbottom, top, 0, bot,
David Lawrence Ramseyf0575cf2005-11-09 23:27:51 +00001210 (i == 1 && bot == openfile->filebot) ? strlen(bot->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001211
1212 /* Copy the paragraph back to the current buffer's filestruct from
1213 * the justify buffer. */
1214 copy_from_filestruct(jusbuffer, jusbottom);
1215
1216 /* Move upward from the last line of the paragraph to the first
1217 * line, putting first_line, edittop, current, and mark_begin at the
1218 * same lines in the copied paragraph that they had in the original
1219 * paragraph. */
David Lawrence Ramsey5d6f1272005-11-10 03:32:59 +00001220 if (openfile->current != openfile->fileage)
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00001221 top = openfile->current->prev;
1222 else
1223 top = openfile->current;
David Lawrence Ramseye8d505b2005-11-10 03:40:45 +00001224 for (i = par_len; i > 0 && top != NULL; i--) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001225 if (top->lineno == fl_lineno_save)
1226 first_line = top;
1227 if (top->lineno == edittop_lineno_save)
1228 openfile->edittop = top;
1229 if (top->lineno == current_lineno_save)
1230 openfile->current = top;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001231#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001232 if (old_mark_set && top->lineno == mb_lineno_save) {
1233 openfile->mark_begin = top;
1234 openfile->mark_begin_x = mark_begin_x_save;
1235 }
1236#endif
1237 top = top->prev;
1238 }
1239
1240 /* Put current_x at the same place in the copied paragraph that it
1241 * had in the original paragraph. */
1242 openfile->current_x = current_x_save;
1243
1244 set_modified();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001245}
1246
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001247/* Find the beginning of the current paragraph if we're in one, or the
1248 * beginning of the next paragraph if we're not. Afterwards, save the
1249 * quote length and paragraph length in *quote and *par. Return TRUE if
David Lawrence Ramsey139fa652006-05-22 01:26:24 +00001250 * we found a paragraph, and FALSE if there was an error or we didn't
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001251 * find a paragraph.
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001252 *
1253 * See the comment at begpar() for more about when a line is the
1254 * beginning of a paragraph. */
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001255bool find_paragraph(size_t *const quote, size_t *const par)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001256{
1257 size_t quote_len;
1258 /* Length of the initial quotation of the paragraph we search
1259 * for. */
1260 size_t par_len;
1261 /* Number of lines in the paragraph we search for. */
1262 filestruct *current_save;
1263 /* The line at the beginning of the paragraph we search for. */
1264 ssize_t current_y_save;
1265 /* The y-coordinate at the beginning of the paragraph we search
1266 * for. */
1267
1268#ifdef HAVE_REGEX_H
1269 if (quoterc != 0) {
1270 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
1271 return FALSE;
1272 }
1273#endif
1274
1275 assert(openfile->current != NULL);
1276
David Lawrence Ramsey1be131a2005-11-11 03:55:52 +00001277 /* If we're at the end of the last line of the file, it means that
1278 * there aren't any paragraphs left, so get out. */
1279 if (openfile->current == openfile->filebot && openfile->current_x ==
1280 strlen(openfile->filebot->data))
1281 return FALSE;
1282
1283 /* If the current line isn't in a paragraph, move forward to the
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001284 * last line of the next paragraph, if any. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001285 if (!inpar(openfile->current)) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001286 do_para_end(FALSE);
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001287
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001288 /* If we end up past the beginning of the line, it means that
1289 * we're at the end of the last line of the file, and the line
1290 * isn't blank, in which case the last line of the file is the
1291 * last line of the next paragraph.
1292 *
1293 * Otherwise, if we end up on a line that's in a paragraph, it
1294 * means that we're on the line after the last line of the next
1295 * paragraph, in which case we should move back to the last line
1296 * of the next paragraph. */
1297 if (openfile->current_x == 0) {
1298 if (!inpar(openfile->current->prev))
1299 return FALSE;
1300 if (openfile->current != openfile->fileage)
1301 openfile->current = openfile->current->prev;
1302 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001303 }
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001304
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001305 /* If the current line isn't the first line of the paragraph, move
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001306 * back to the first line of the paragraph. */
1307 if (!begpar(openfile->current))
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001308 do_para_begin(FALSE);
1309
1310 /* Now current is the first line of the paragraph. Set quote_len to
1311 * the quotation length of that line, and set par_len to the number
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001312 * of lines in this paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001313 quote_len = quote_length(openfile->current->data);
1314 current_save = openfile->current;
1315 current_y_save = openfile->current_y;
1316 do_para_end(FALSE);
1317 par_len = openfile->current->lineno - current_save->lineno;
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00001318
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00001319 /* If we end up past the beginning of the line, it means that we're
1320 * at the end of the last line of the file, and the line isn't
1321 * blank, in which case the last line of the file is part of the
1322 * paragraph. */
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00001323 if (openfile->current_x > 0)
1324 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001325 openfile->current = current_save;
1326 openfile->current_y = current_y_save;
1327
1328 /* Save the values of quote_len and par_len. */
1329 assert(quote != NULL && par != NULL);
1330
1331 *quote = quote_len;
1332 *par = par_len;
1333
1334 return TRUE;
1335}
1336
1337/* If full_justify is TRUE, justify the entire file. Otherwise, justify
1338 * the current paragraph. */
1339void do_justify(bool full_justify)
1340{
1341 filestruct *first_par_line = NULL;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001342 /* Will be the first line of the justified paragraph(s), if any.
1343 * For restoring after unjustify. */
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001344 filestruct *last_par_line = NULL;
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001345 /* Will be the line after the last line of the justified
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001346 * paragraph(s), if any. Also for restoring after unjustify. */
David Lawrence Ramsey82b5deb2005-11-10 06:07:57 +00001347 bool filebot_inpar = FALSE;
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001348 /* Whether the text at filebot is part of the current
1349 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001350
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00001351 /* We save these variables to be restored if the user
1352 * unjustifies. */
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00001353 filestruct *edittop_save = openfile->edittop;
1354 filestruct *current_save = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001355 size_t current_x_save = openfile->current_x;
1356 size_t pww_save = openfile->placewewant;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001357 size_t totsize_save = openfile->totsize;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001358#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001359 filestruct *mark_begin_save = openfile->mark_begin;
1360 size_t mark_begin_x_save = openfile->mark_begin_x;
1361#endif
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00001362 bool modified_save = openfile->modified;
1363
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001364 int kbinput;
1365 bool meta_key, func_key, s_or_t, ran_func, finished;
1366
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001367 /* Move to the beginning of the current line, so that justifying at
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00001368 * the end of the last line of the file, if that line isn't blank,
1369 * will work the first time through. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001370 openfile->current_x = 0;
1371
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001372 /* If we're justifying the entire file, start at the beginning. */
1373 if (full_justify)
1374 openfile->current = openfile->fileage;
1375
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001376 while (TRUE) {
1377 size_t i;
1378 /* Generic loop variable. */
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001379 filestruct *curr_first_par_line;
1380 /* The first line of the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001381 size_t quote_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001382 /* Length of the initial quotation of the current
1383 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001384 size_t indent_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001385 /* Length of the initial indentation of the current
1386 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001387 size_t par_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001388 /* Number of lines in the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001389 ssize_t break_pos;
1390 /* Where we will break lines. */
1391 char *indent_string;
1392 /* The first indentation that doesn't match the initial
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001393 * indentation of the current paragraph. This is put at the
1394 * beginning of every line broken off the first justified
1395 * line of the paragraph. Note that this works because a
1396 * paragraph can only contain two indentations at most: the
1397 * initial one, and a different one starting on a line after
1398 * the first. See the comment at begpar() for more about
1399 * when a line is part of a paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001400
1401 /* Find the first line of the paragraph to be justified. That
1402 * is the start of this paragraph if we're in one, or the start
1403 * of the next otherwise. Save the quote length and paragraph
1404 * length (number of lines). Don't refresh the screen yet,
1405 * since we'll do that after we justify.
1406 *
1407 * If the search failed, we do one of two things. If we're
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00001408 * justifying the whole file, and we've found at least one
1409 * paragraph, it means that we should justify all the way to the
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001410 * last line of the file, so set the last line of the text to be
1411 * justified to the last line of the file and break out of the
1412 * loop. Otherwise, it means that there are no paragraph(s) to
1413 * justify, so refresh the screen and get out. */
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00001414 if (!find_paragraph(&quote_len, &par_len)) {
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00001415 if (full_justify && first_par_line != NULL) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001416 last_par_line = openfile->filebot;
1417 break;
1418 } else {
1419 edit_refresh();
1420 return;
1421 }
1422 }
1423
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00001424 /* par_len will be one greater than the number of lines between
1425 * current and filebot if filebot is the last line in the
1426 * paragraph. Set filebot_inpar to TRUE if this is the case. */
1427 filebot_inpar = (openfile->current->lineno + par_len ==
1428 openfile->filebot->lineno + 1);
1429
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001430 /* If we haven't already done it, move the original paragraph(s)
1431 * to the justify buffer, splice a copy of the original
1432 * paragraph(s) into the file in the same place, and set
1433 * first_par_line to the first line of the copy. */
1434 if (first_par_line == NULL) {
1435 backup_lines(openfile->current, full_justify ?
David Lawrence Ramsey53f641f2005-11-10 21:57:56 +00001436 openfile->filebot->lineno - openfile->current->lineno +
1437 ((openfile->filebot->data[0] != '\0') ? 1 : 0) :
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001438 par_len);
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00001439 first_par_line = openfile->current;
1440 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001441
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001442 /* Set curr_first_par_line to the first line of the current
1443 * paragraph. */
1444 curr_first_par_line = openfile->current;
1445
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001446 /* Initialize indent_string to a blank string. */
1447 indent_string = mallocstrcpy(NULL, "");
1448
1449 /* Find the first indentation in the paragraph that doesn't
David Lawrence Ramsey8602fd62006-05-28 18:43:21 +00001450 * match the indentation of the first line, and save it in
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001451 * indent_string. If all the indentations are the same, save
1452 * the indentation of the first line in indent_string. */
1453 {
1454 const filestruct *indent_line = openfile->current;
1455 bool past_first_line = FALSE;
1456
1457 for (i = 0; i < par_len; i++) {
1458 indent_len = quote_len +
1459 indent_length(indent_line->data + quote_len);
1460
1461 if (indent_len != strlen(indent_string)) {
1462 indent_string = mallocstrncpy(indent_string,
1463 indent_line->data, indent_len + 1);
1464 indent_string[indent_len] = '\0';
1465
1466 if (past_first_line)
1467 break;
1468 }
1469
1470 if (indent_line == openfile->current)
1471 past_first_line = TRUE;
1472
1473 indent_line = indent_line->next;
1474 }
1475 }
1476
1477 /* Now tack all the lines of the paragraph together, skipping
1478 * the quoting and indentation on all lines after the first. */
1479 for (i = 0; i < par_len - 1; i++) {
1480 filestruct *next_line = openfile->current->next;
1481 size_t line_len = strlen(openfile->current->data);
1482 size_t next_line_len =
1483 strlen(openfile->current->next->data);
1484
1485 indent_len = quote_len +
1486 indent_length(openfile->current->next->data +
1487 quote_len);
1488
1489 next_line_len -= indent_len;
1490 openfile->totsize -= indent_len;
1491
1492 /* We're just about to tack the next line onto this one. If
1493 * this line isn't empty, make sure it ends in a space. */
1494 if (line_len > 0 &&
1495 openfile->current->data[line_len - 1] != ' ') {
1496 line_len++;
1497 openfile->current->data =
1498 charealloc(openfile->current->data,
1499 line_len + 1);
1500 openfile->current->data[line_len - 1] = ' ';
1501 openfile->current->data[line_len] = '\0';
1502 openfile->totsize++;
1503 }
1504
1505 openfile->current->data =
1506 charealloc(openfile->current->data, line_len +
1507 next_line_len + 1);
1508 strcat(openfile->current->data, next_line->data +
1509 indent_len);
1510
David Lawrence Ramsey9bedc4b2005-11-09 19:51:48 +00001511 /* Don't destroy edittop or filebot! */
David Lawrence Ramsey32bd29e2005-11-09 03:44:23 +00001512 if (next_line == openfile->edittop)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001513 openfile->edittop = openfile->current;
David Lawrence Ramsey9bedc4b2005-11-09 19:51:48 +00001514 if (next_line == openfile->filebot)
1515 openfile->filebot = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001516
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001517#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001518 /* Adjust the mark coordinates to compensate for the change
1519 * in the next line. */
1520 if (openfile->mark_set && openfile->mark_begin ==
1521 next_line) {
1522 openfile->mark_begin = openfile->current;
1523 openfile->mark_begin_x += line_len - indent_len;
1524 }
1525#endif
1526
1527 unlink_node(next_line);
1528 delete_node(next_line);
1529
1530 /* If we've removed the next line, we need to go through
1531 * this line again. */
1532 i--;
1533
1534 par_len--;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001535 openfile->totsize--;
1536 }
1537
1538 /* Call justify_format() on the paragraph, which will remove
1539 * excess spaces from it and change all blank characters to
1540 * spaces. */
1541 justify_format(openfile->current, quote_len +
1542 indent_length(openfile->current->data + quote_len));
1543
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001544 while (par_len > 0 && strlenpt(openfile->current->data) >
1545 fill) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001546 size_t line_len = strlen(openfile->current->data);
1547
1548 indent_len = strlen(indent_string);
1549
1550 /* If this line is too long, try to wrap it to the next line
1551 * to make it short enough. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001552 break_pos = break_line(openfile->current->data + indent_len,
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001553 fill - strnlenpt(openfile->current->data, indent_len)
1554#ifndef DISABLE_HELP
1555 , FALSE
1556#endif
1557 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001558
1559 /* We can't break the line, or don't need to, so get out. */
1560 if (break_pos == -1 || break_pos + indent_len == line_len)
1561 break;
1562
1563 /* Move forward to the character after the indentation and
1564 * just after the space. */
1565 break_pos += indent_len + 1;
1566
1567 assert(break_pos <= line_len);
1568
1569 /* Make a new line, and copy the text after where we're
1570 * going to break this line to the beginning of the new
1571 * line. */
1572 splice_node(openfile->current,
1573 make_new_node(openfile->current),
1574 openfile->current->next);
1575
1576 /* If this paragraph is non-quoted, and autoindent isn't
1577 * turned on, set the indentation length to zero so that the
1578 * indentation is treated as part of the line. */
1579 if (quote_len == 0
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001580#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001581 && !ISSET(AUTOINDENT)
1582#endif
1583 )
1584 indent_len = 0;
1585
1586 /* Copy the text after where we're going to break the
1587 * current line to the next line. */
1588 openfile->current->next->data = charalloc(indent_len + 1 +
1589 line_len - break_pos);
1590 strncpy(openfile->current->next->data, indent_string,
1591 indent_len);
1592 strcpy(openfile->current->next->data + indent_len,
1593 openfile->current->data + break_pos);
1594
1595 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001596 openfile->totsize += indent_len + 1;
1597
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001598#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001599 /* Adjust the mark coordinates to compensate for the change
1600 * in the current line. */
1601 if (openfile->mark_set && openfile->mark_begin ==
1602 openfile->current && openfile->mark_begin_x >
1603 break_pos) {
1604 openfile->mark_begin = openfile->current->next;
1605 openfile->mark_begin_x -= break_pos - indent_len;
1606 }
1607#endif
1608
1609 /* Break the current line. */
1610 null_at(&openfile->current->data, break_pos);
1611
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001612 /* If the current line is the last line of the file, move
David Lawrence Ramseyb885c9c2005-11-10 05:20:25 +00001613 * the last line of the file down to the next line. */
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001614 if (openfile->filebot == openfile->current)
1615 openfile->filebot = openfile->filebot->next;
1616
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001617 /* Go to the next line. */
1618 par_len--;
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001619 openfile->current_y++;
1620 openfile->current = openfile->current->next;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001621 }
1622
1623 /* We're done breaking lines, so we don't need indent_string
1624 * anymore. */
1625 free(indent_string);
1626
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00001627 /* Go to the next line, if possible. If there is no next line,
1628 * move to the end of the current line. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00001629 if (openfile->current != openfile->filebot) {
1630 openfile->current_y++;
1631 openfile->current = openfile->current->next;
1632 } else
1633 openfile->current_x = strlen(openfile->current->data);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001634
David Lawrence Ramseya6854682005-11-30 21:19:42 +00001635 /* Renumber the lines of the now-justified current paragraph,
1636 * since both find_paragraph() and edit_refresh() need the line
1637 * numbers to be right. */
1638 renumber(curr_first_par_line);
David Lawrence Ramseyad1b64c2005-11-29 19:00:09 +00001639
1640 /* We've just finished justifying the paragraph. If we're not
1641 * justifying the entire file, break out of the loop.
1642 * Otherwise, continue the loop so that we justify all the
1643 * paragraphs in the file. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001644 if (!full_justify)
1645 break;
1646 }
1647
1648 /* We are now done justifying the paragraph or the file, so clean
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001649 * up. current_y and totsize have been maintained above. If we
David Lawrence Ramseyad1b64c2005-11-29 19:00:09 +00001650 * actually justified something, set last_par_line to the new end of
1651 * the paragraph. */
1652 if (first_par_line != NULL)
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001653 last_par_line = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001654
1655 edit_refresh();
1656
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00001657#ifndef NANO_TINY
David Lawrence Ramsey1c5af642006-05-10 15:15:06 +00001658 /* We're going to set jump_buf so that we return here after a
1659 * SIGWINCH instead of to main(). Indicate this. */
1660 jump_buf_main = FALSE;
1661
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00001662 /* Return here after a SIGWINCH. */
David Lawrence Ramsey1c5af642006-05-10 15:15:06 +00001663 sigsetjmp(jump_buf, 1);
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00001664#endif
1665
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001666 statusbar(_("Can now UnJustify!"));
1667
1668 /* If constant cursor position display is on, make sure the current
1669 * cursor position will be properly displayed on the statusbar. */
1670 if (ISSET(CONST_UPDATE))
1671 do_cursorpos(TRUE);
1672
1673 /* Display the shortcut list with UnJustify. */
1674 shortcut_init(TRUE);
1675 display_main_list();
1676
1677 /* Now get a keystroke and see if it's unjustify. If not, put back
1678 * the keystroke and return. */
1679 kbinput = do_input(&meta_key, &func_key, &s_or_t, &ran_func,
1680 &finished, FALSE);
1681
David Lawrence Ramseyb22c80a2006-05-06 13:41:59 +00001682 if (s_or_t && kbinput == NANO_UNJUSTIFY_KEY) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001683 /* Splice the justify buffer back into the file, but only if we
1684 * actually justified something. */
1685 if (first_par_line != NULL) {
1686 filestruct *top_save;
1687
1688 /* Partition the filestruct so that it contains only the
1689 * text of the justified paragraph. */
1690 filepart = partition_filestruct(first_par_line, 0,
David Lawrence Ramseyccd1b7b2005-11-18 20:21:48 +00001691 last_par_line, filebot_inpar ?
1692 strlen(last_par_line->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001693
1694 /* Remove the text of the justified paragraph, and
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00001695 * replace it with the text in the justify buffer. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001696 free_filestruct(openfile->fileage);
1697 openfile->fileage = jusbuffer;
1698 openfile->filebot = jusbottom;
1699
1700 top_save = openfile->fileage;
1701
1702 /* Unpartition the filestruct so that it contains all the
1703 * text again. Note that the justified paragraph has been
1704 * replaced with the unjustified paragraph. */
1705 unpartition_filestruct(&filepart);
1706
1707 /* Renumber starting with the beginning line of the old
1708 * partition. */
1709 renumber(top_save);
1710
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00001711 /* Restore the justify we just did (ungrateful user!). */
1712 openfile->edittop = edittop_save;
1713 openfile->current = current_save;
1714 openfile->current_x = current_x_save;
1715 openfile->placewewant = pww_save;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001716 openfile->totsize = totsize_save;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001717#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001718 if (openfile->mark_set) {
1719 openfile->mark_begin = mark_begin_save;
1720 openfile->mark_begin_x = mark_begin_x_save;
1721 }
1722#endif
1723 openfile->modified = modified_save;
1724
1725 /* Clear the justify buffer. */
1726 jusbuffer = NULL;
1727
1728 if (!openfile->modified)
1729 titlebar(NULL);
1730 edit_refresh();
1731 }
1732 } else {
1733 unget_kbinput(kbinput, meta_key, func_key);
1734
1735 /* Blow away the text in the justify buffer. */
1736 free_filestruct(jusbuffer);
1737 jusbuffer = NULL;
1738 }
1739
1740 blank_statusbar();
1741
1742 /* Display the shortcut list with UnCut. */
1743 shortcut_init(FALSE);
1744 display_main_list();
1745}
1746
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001747/* Justify the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001748void do_justify_void(void)
1749{
1750 do_justify(FALSE);
1751}
1752
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001753/* Justify the entire file. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001754void do_full_justify(void)
1755{
1756 do_justify(TRUE);
1757}
1758#endif /* !DISABLE_JUSTIFY */
1759
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001760#ifndef DISABLE_SPELLER
1761/* A word is misspelled in the file. Let the user replace it. We
1762 * return FALSE if the user cancels. */
1763bool do_int_spell_fix(const char *word)
1764{
1765 char *save_search, *save_replace;
1766 size_t match_len, current_x_save = openfile->current_x;
1767 size_t pww_save = openfile->placewewant;
1768 filestruct *edittop_save = openfile->edittop;
1769 filestruct *current_save = openfile->current;
1770 /* Save where we are. */
1771 bool canceled = FALSE;
1772 /* The return value. */
1773 bool case_sens_set = ISSET(CASE_SENSITIVE);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001774#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001775 bool backwards_search_set = ISSET(BACKWARDS_SEARCH);
1776#endif
1777#ifdef HAVE_REGEX_H
1778 bool regexp_set = ISSET(USE_REGEXP);
1779#endif
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001780#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001781 bool old_mark_set = openfile->mark_set;
1782 bool added_magicline = FALSE;
1783 /* Whether we added a magicline after filebot. */
1784 bool right_side_up = FALSE;
1785 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
1786 * FALSE if (current, current_x) is. */
1787 filestruct *top, *bot;
1788 size_t top_x, bot_x;
1789#endif
1790
1791 /* Make sure spell-check is case sensitive. */
1792 SET(CASE_SENSITIVE);
1793
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001794#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001795 /* Make sure spell-check goes forward only. */
1796 UNSET(BACKWARDS_SEARCH);
1797#endif
1798#ifdef HAVE_REGEX_H
1799 /* Make sure spell-check doesn't use regular expressions. */
1800 UNSET(USE_REGEXP);
1801#endif
1802
1803 /* Save the current search/replace strings. */
1804 search_init_globals();
1805 save_search = last_search;
1806 save_replace = last_replace;
1807
1808 /* Set the search/replace strings to the misspelled word. */
1809 last_search = mallocstrcpy(NULL, word);
1810 last_replace = mallocstrcpy(NULL, word);
1811
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001812#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001813 if (old_mark_set) {
1814 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00001815 * contains only the marked text; if the NO_NEWLINES flag isn't
1816 * set, keep track of whether the text will have a magicline
1817 * added when we're done correcting misspelled words; and
1818 * turn the mark off. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001819 mark_order((const filestruct **)&top, &top_x,
1820 (const filestruct **)&bot, &bot_x, &right_side_up);
1821 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00001822 if (!ISSET(NO_NEWLINES))
1823 added_magicline = (openfile->filebot->data[0] != '\0');
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001824 openfile->mark_set = FALSE;
1825 }
1826#endif
1827
1828 /* Start from the top of the file. */
1829 openfile->edittop = openfile->fileage;
1830 openfile->current = openfile->fileage;
1831 openfile->current_x = (size_t)-1;
1832 openfile->placewewant = 0;
1833
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001834 /* Find the first whole occurrence of word. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001835 findnextstr_wrap_reset();
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001836 while (findnextstr(TRUE, FALSE, openfile->fileage, 0, word,
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001837 &match_len)) {
1838 if (is_whole_word(openfile->current_x, openfile->current->data,
1839 word)) {
1840 size_t xpt = xplustabs();
1841 char *exp_word = display_string(openfile->current->data,
1842 xpt, strnlenpt(openfile->current->data,
1843 openfile->current_x + match_len) - xpt, FALSE);
1844
1845 edit_refresh();
1846
1847 do_replace_highlight(TRUE, exp_word);
1848
1849 /* Allow all instances of the word to be corrected. */
David Lawrence Ramsey9d8c2842006-02-07 21:11:05 +00001850 canceled = (do_prompt(FALSE,
1851#ifndef DISABLE_TABCOMP
1852 TRUE,
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001853#endif
David Lawrence Ramsey9d8c2842006-02-07 21:11:05 +00001854 spell_list, word,
1855#ifndef NANO_TINY
1856 NULL,
1857#endif
David Lawrence Ramsey68160072006-02-18 21:32:29 +00001858 edit_refresh, _("Edit a replacement")) == -1);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001859
1860 do_replace_highlight(FALSE, exp_word);
1861
1862 free(exp_word);
1863
1864 if (!canceled && strcmp(word, answer) != 0) {
1865 openfile->current_x--;
David Lawrence Ramseyc5c52302005-11-15 23:45:29 +00001866 do_replace_loop(TRUE, &canceled, openfile->current,
1867 &openfile->current_x, word);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001868 }
1869
1870 break;
1871 }
1872 }
1873
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001874#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001875 if (old_mark_set) {
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00001876 /* If the mark was on, the NO_NEWLINES flag isn't set, and we
1877 * added a magicline, remove it now. */
1878 if (!ISSET(NO_NEWLINES) && added_magicline)
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001879 remove_magicline();
1880
1881 /* Put the beginning and the end of the mark at the beginning
1882 * and the end of the spell-checked text. */
1883 if (openfile->fileage == openfile->filebot)
1884 bot_x += top_x;
1885 if (right_side_up) {
1886 openfile->mark_begin_x = top_x;
1887 current_x_save = bot_x;
1888 } else {
1889 current_x_save = top_x;
1890 openfile->mark_begin_x = bot_x;
1891 }
1892
1893 /* Unpartition the filestruct so that it contains all the text
1894 * again, and turn the mark back on. */
1895 unpartition_filestruct(&filepart);
1896 openfile->mark_set = TRUE;
1897 }
1898#endif
1899
1900 /* Restore the search/replace strings. */
1901 free(last_search);
1902 last_search = save_search;
1903 free(last_replace);
1904 last_replace = save_replace;
1905
1906 /* Restore where we were. */
1907 openfile->edittop = edittop_save;
1908 openfile->current = current_save;
1909 openfile->current_x = current_x_save;
1910 openfile->placewewant = pww_save;
1911
1912 /* Restore case sensitivity setting. */
1913 if (!case_sens_set)
1914 UNSET(CASE_SENSITIVE);
1915
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001916#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001917 /* Restore search/replace direction. */
1918 if (backwards_search_set)
1919 SET(BACKWARDS_SEARCH);
1920#endif
1921#ifdef HAVE_REGEX_H
1922 /* Restore regular expression usage setting. */
1923 if (regexp_set)
1924 SET(USE_REGEXP);
1925#endif
1926
1927 return !canceled;
1928}
1929
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001930/* Internal (integrated) spell checking using the spell program,
1931 * filtered through the sort and uniq programs. Return NULL for normal
1932 * termination, and the error string otherwise. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001933const char *do_int_speller(const char *tempfile_name)
1934{
1935 char *read_buff, *read_buff_ptr, *read_buff_word;
1936 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
1937 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
1938 pid_t pid_spell, pid_sort, pid_uniq;
1939 int spell_status, sort_status, uniq_status;
1940
1941 /* Create all three pipes up front. */
1942 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 ||
1943 pipe(uniq_fd) == -1)
1944 return _("Could not create pipe");
1945
1946 statusbar(_("Creating misspelled word list, please wait..."));
1947
1948 /* A new process to run spell in. */
1949 if ((pid_spell = fork()) == 0) {
1950 /* Child continues (i.e, future spell process). */
1951 close(spell_fd[0]);
1952
1953 /* Replace the standard input with the temp file. */
1954 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1955 goto close_pipes_and_exit;
1956
1957 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1958 goto close_pipes_and_exit;
1959
1960 close(tempfile_fd);
1961
1962 /* Send spell's standard output to the pipe. */
1963 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1964 goto close_pipes_and_exit;
1965
1966 close(spell_fd[1]);
1967
David Lawrence Ramsey3239ff22005-11-29 20:01:06 +00001968 /* Start the spell program; we are using $PATH. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00001969 execlp("spell", "spell", NULL);
1970
1971 /* This should not be reached if spell is found. */
1972 exit(1);
1973 }
1974
1975 /* Parent continues here. */
1976 close(spell_fd[1]);
1977
1978 /* A new process to run sort in. */
1979 if ((pid_sort = fork()) == 0) {
1980 /* Child continues (i.e, future spell process). Replace the
1981 * standard input with the standard output of the old pipe. */
1982 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1983 goto close_pipes_and_exit;
1984
1985 close(spell_fd[0]);
1986
1987 /* Send sort's standard output to the new pipe. */
1988 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1989 goto close_pipes_and_exit;
1990
1991 close(sort_fd[1]);
1992
1993 /* Start the sort program. Use -f to remove mixed case. If
1994 * this isn't portable, let me know. */
1995 execlp("sort", "sort", "-f", NULL);
1996
1997 /* This should not be reached if sort is found. */
1998 exit(1);
1999 }
2000
2001 close(spell_fd[0]);
2002 close(sort_fd[1]);
2003
2004 /* A new process to run uniq in. */
2005 if ((pid_uniq = fork()) == 0) {
2006 /* Child continues (i.e, future uniq process). Replace the
2007 * standard input with the standard output of the old pipe. */
2008 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
2009 goto close_pipes_and_exit;
2010
2011 close(sort_fd[0]);
2012
2013 /* Send uniq's standard output to the new pipe. */
2014 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2015 goto close_pipes_and_exit;
2016
2017 close(uniq_fd[1]);
2018
2019 /* Start the uniq program; we are using PATH. */
2020 execlp("uniq", "uniq", NULL);
2021
2022 /* This should not be reached if uniq is found. */
2023 exit(1);
2024 }
2025
2026 close(sort_fd[0]);
2027 close(uniq_fd[1]);
2028
2029 /* The child process was not forked successfully. */
2030 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
2031 close(uniq_fd[0]);
2032 return _("Could not fork");
2033 }
2034
2035 /* Get the system pipe buffer size. */
2036 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
2037 close(uniq_fd[0]);
2038 return _("Could not get size of pipe buffer");
2039 }
2040
2041 /* Read in the returned spelling errors. */
2042 read_buff_read = 0;
2043 read_buff_size = pipe_buff_size + 1;
2044 read_buff = read_buff_ptr = charalloc(read_buff_size);
2045
2046 while ((bytesread = read(uniq_fd[0], read_buff_ptr,
2047 pipe_buff_size)) > 0) {
2048 read_buff_read += bytesread;
2049 read_buff_size += pipe_buff_size;
2050 read_buff = read_buff_ptr = charealloc(read_buff,
2051 read_buff_size);
2052 read_buff_ptr += read_buff_read;
2053 }
2054
2055 *read_buff_ptr = '\0';
2056 close(uniq_fd[0]);
2057
2058 /* Process the spelling errors. */
2059 read_buff_word = read_buff_ptr = read_buff;
2060
2061 while (*read_buff_ptr != '\0') {
2062 if ((*read_buff_ptr == '\r') || (*read_buff_ptr == '\n')) {
2063 *read_buff_ptr = '\0';
2064 if (read_buff_word != read_buff_ptr) {
2065 if (!do_int_spell_fix(read_buff_word)) {
2066 read_buff_word = read_buff_ptr;
2067 break;
2068 }
2069 }
2070 read_buff_word = read_buff_ptr + 1;
2071 }
2072 read_buff_ptr++;
2073 }
2074
2075 /* Special case: the last word doesn't end with '\r' or '\n'. */
2076 if (read_buff_word != read_buff_ptr)
2077 do_int_spell_fix(read_buff_word);
2078
2079 free(read_buff);
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002080 search_replace_abort();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002081 edit_refresh();
2082
2083 /* Process the end of the spell process. */
2084 waitpid(pid_spell, &spell_status, 0);
2085 waitpid(pid_sort, &sort_status, 0);
2086 waitpid(pid_uniq, &uniq_status, 0);
2087
2088 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
2089 return _("Error invoking \"spell\"");
2090
2091 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
2092 return _("Error invoking \"sort -f\"");
2093
2094 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
2095 return _("Error invoking \"uniq\"");
2096
2097 /* Otherwise... */
2098 return NULL;
2099
2100 close_pipes_and_exit:
2101 /* Don't leak any handles. */
2102 close(tempfile_fd);
2103 close(spell_fd[0]);
2104 close(spell_fd[1]);
2105 close(sort_fd[0]);
2106 close(sort_fd[1]);
2107 close(uniq_fd[0]);
2108 close(uniq_fd[1]);
2109 exit(1);
2110}
2111
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002112/* External (alternate) spell checking. Return NULL for normal
2113 * termination, and the error string otherwise. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002114const char *do_alt_speller(char *tempfile_name)
2115{
2116 int alt_spell_status;
2117 size_t current_x_save = openfile->current_x;
2118 size_t pww_save = openfile->placewewant;
2119 ssize_t current_y_save = openfile->current_y;
2120 ssize_t lineno_save = openfile->current->lineno;
2121 pid_t pid_spell;
2122 char *ptr;
2123 static int arglen = 3;
2124 static char **spellargs = NULL;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002125#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002126 bool old_mark_set = openfile->mark_set;
2127 bool added_magicline = FALSE;
2128 /* Whether we added a magicline after filebot. */
2129 bool right_side_up = FALSE;
2130 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
2131 * FALSE if (current, current_x) is. */
2132 filestruct *top, *bot;
2133 size_t top_x, bot_x;
2134 ssize_t mb_lineno_save = 0;
2135 /* We're going to close the current file, and open the output of
2136 * the alternate spell command. The line that mark_begin points
2137 * to will be freed, so we save the line number and restore it
2138 * afterwards. */
2139 size_t totsize_save = openfile->totsize;
2140 /* Our saved value of totsize, used when we spell-check a marked
2141 * selection. */
2142
2143 if (old_mark_set) {
2144 /* If the mark is on, save the number of the line it starts on,
2145 * and then turn the mark off. */
2146 mb_lineno_save = openfile->mark_begin->lineno;
2147 openfile->mark_set = FALSE;
2148 }
2149#endif
2150
2151 endwin();
2152
2153 /* Set up an argument list to pass execvp(). */
2154 if (spellargs == NULL) {
2155 spellargs = (char **)nmalloc(arglen * sizeof(char *));
2156
2157 spellargs[0] = strtok(alt_speller, " ");
2158 while ((ptr = strtok(NULL, " ")) != NULL) {
2159 arglen++;
2160 spellargs = (char **)nrealloc(spellargs, arglen *
2161 sizeof(char *));
2162 spellargs[arglen - 3] = ptr;
2163 }
2164 spellargs[arglen - 1] = NULL;
2165 }
2166 spellargs[arglen - 2] = tempfile_name;
2167
2168 /* Start a new process for the alternate speller. */
2169 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey2e2112c2005-11-29 05:39:31 +00002170 /* Start alternate spell program; we are using $PATH. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002171 execvp(spellargs[0], spellargs);
2172
2173 /* Should not be reached, if alternate speller is found!!! */
2174 exit(1);
2175 }
2176
2177 /* If we couldn't fork, get out. */
2178 if (pid_spell < 0)
2179 return _("Could not fork");
2180
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002181#ifndef NANO_TINY
David Lawrence Ramseyb18482e2005-07-26 00:06:34 +00002182 /* Don't handle a pending SIGWINCH until the alternate spell checker
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002183 * is finished and we've loaded the spell-checked file back in. */
David Lawrence Ramseyb18482e2005-07-26 00:06:34 +00002184 allow_pending_sigwinch(FALSE);
2185#endif
2186
2187 /* Wait for the alternate spell checker to finish. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002188 wait(&alt_spell_status);
2189
David Lawrence Ramsey84fdb902005-08-14 20:08:49 +00002190 /* Reenter curses mode. */
2191 doupdate();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002192
2193 /* Restore the terminal to its previous state. */
2194 terminal_init();
2195
2196 /* Turn the cursor back on for sure. */
2197 curs_set(1);
2198
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002199 /* The screen might have been resized. If it has, reinitialize all
2200 * the windows based on the new screen dimensions. */
2201 window_init();
2202
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002203 if (!WIFEXITED(alt_spell_status) ||
2204 WEXITSTATUS(alt_spell_status) != 0) {
2205 char *altspell_error;
2206 char *invoke_error = _("Error invoking \"%s\"");
2207
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002208#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002209 /* Turn the mark back on if it was on before. */
2210 openfile->mark_set = old_mark_set;
2211#endif
2212
2213 altspell_error =
2214 charalloc(strlen(invoke_error) +
2215 strlen(alt_speller) + 1);
2216 sprintf(altspell_error, invoke_error, alt_speller);
2217 return altspell_error;
2218 }
2219
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002220#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002221 if (old_mark_set) {
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002222 /* If the mark is on, partition the filestruct so that it
2223 * contains only the marked text; if the NO_NEWLINES flag isn't
2224 * set, keep track of whether the text will have a magicline
2225 * added when we're done correcting misspelled words; and
2226 * turn the mark off. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002227 mark_order((const filestruct **)&top, &top_x,
2228 (const filestruct **)&bot, &bot_x, &right_side_up);
2229 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002230 if (!ISSET(NO_NEWLINES))
2231 added_magicline = (openfile->filebot->data[0] != '\0');
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002232
2233 /* Get the number of characters in the marked text, and subtract
2234 * it from the saved value of totsize. */
2235 totsize_save -= get_totsize(top, bot);
2236 }
2237#endif
2238
David Lawrence Ramsey9c984e82005-11-08 19:15:58 +00002239 /* Replace the text of the current buffer with the spell-checked
2240 * text. */
2241 replace_buffer(tempfile_name);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002242
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002243#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002244 if (old_mark_set) {
2245 filestruct *top_save = openfile->fileage;
2246
David Lawrence Ramsey1e0e2352005-11-08 18:34:12 +00002247 /* If the mark was on, the NO_NEWLINES flag isn't set, and we
2248 * added a magicline, remove it now. */
2249 if (!ISSET(NO_NEWLINES) && added_magicline)
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002250 remove_magicline();
2251
2252 /* Put the beginning and the end of the mark at the beginning
2253 * and the end of the spell-checked text. */
2254 if (openfile->fileage == openfile->filebot)
2255 bot_x += top_x;
2256 if (right_side_up) {
2257 openfile->mark_begin_x = top_x;
2258 current_x_save = bot_x;
2259 } else {
2260 current_x_save = top_x;
2261 openfile->mark_begin_x = bot_x;
2262 }
2263
2264 /* Unpartition the filestruct so that it contains all the text
2265 * again. Note that we've replaced the marked text originally
2266 * in the partition with the spell-checked marked text in the
2267 * temp file. */
2268 unpartition_filestruct(&filepart);
2269
2270 /* Renumber starting with the beginning line of the old
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002271 * partition. Also add the number of characters in the
2272 * spell-checked marked text to the saved value of totsize, and
2273 * then make that saved value the actual value. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002274 renumber(top_save);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002275 totsize_save += openfile->totsize;
2276 openfile->totsize = totsize_save;
2277
2278 /* Assign mark_begin to the line where the mark began before. */
2279 do_gotopos(mb_lineno_save, openfile->mark_begin_x,
2280 current_y_save, 0);
2281 openfile->mark_begin = openfile->current;
2282
2283 /* Assign mark_begin_x to the location in mark_begin where the
2284 * mark began before, adjusted for any shortening of the
2285 * line. */
2286 openfile->mark_begin_x = openfile->current_x;
2287
2288 /* Turn the mark back on. */
2289 openfile->mark_set = TRUE;
2290 }
2291#endif
2292
2293 /* Go back to the old position, and mark the file as modified. */
2294 do_gotopos(lineno_save, current_x_save, current_y_save, pww_save);
2295 set_modified();
2296
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002297#ifndef NANO_TINY
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00002298 /* Handle a pending SIGWINCH again. */
2299 allow_pending_sigwinch(TRUE);
2300#endif
2301
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002302 return NULL;
2303}
2304
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002305/* Spell check the current file. If an alternate spell checker is
2306 * specified, use it. Otherwise, use the internal spell checker. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002307void do_spell(void)
2308{
2309 int i;
2310 FILE *temp_file;
2311 char *temp = safe_tempfile(&temp_file);
2312 const char *spell_msg;
2313
2314 if (temp == NULL) {
David Lawrence Ramseyf0e3ca62006-05-03 13:11:00 +00002315 statusbar(_("Error writing temp file: %s"), strerror(errno));
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002316 return;
2317 }
2318
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002319#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002320 if (openfile->mark_set)
David Lawrence Ramseye014fbd2005-08-29 19:11:26 +00002321 i = write_marked_file(temp, temp_file, TRUE, OVERWRITE);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002322 else
2323#endif
David Lawrence Ramseye014fbd2005-08-29 19:11:26 +00002324 i = write_file(temp, temp_file, TRUE, OVERWRITE, FALSE);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002325
2326 if (i == -1) {
2327 statusbar(_("Error writing temp file: %s"), strerror(errno));
2328 free(temp);
2329 return;
2330 }
2331
2332 spell_msg = (alt_speller != NULL) ? do_alt_speller(temp) :
2333 do_int_speller(temp);
2334 unlink(temp);
2335 free(temp);
2336
David Lawrence Ramseyf32e1dd2006-06-09 17:09:51 +00002337 currshortcut = main_list;
2338
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002339 /* If the spell-checker printed any error messages onscreen, make
2340 * sure that they're cleared off. */
David Lawrence Ramseyf32e1dd2006-06-09 17:09:51 +00002341 total_refresh();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002342
2343 if (spell_msg != NULL) {
2344 if (errno == 0)
2345 /* Don't display an error message of "Success". */
2346 statusbar(_("Spell checking failed: %s"), spell_msg);
2347 else
2348 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
2349 strerror(errno));
2350 } else
2351 statusbar(_("Finished checking spelling"));
2352}
2353#endif /* !DISABLE_SPELLER */
2354
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002355#ifndef NANO_TINY
David Lawrence Ramseyd7f0fe92005-08-10 22:51:49 +00002356/* Our own version of "wc". Note that its character counts are in
2357 * multibyte characters instead of single-byte characters. */
David Lawrence Ramsey8e942342005-07-25 04:21:46 +00002358void do_wordlinechar_count(void)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002359{
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002360 size_t words = 0, chars = 0;
2361 ssize_t lines = 0;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002362 size_t current_x_save = openfile->current_x;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002363 size_t pww_save = openfile->placewewant;
2364 filestruct *current_save = openfile->current;
2365 bool old_mark_set = openfile->mark_set;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002366 filestruct *top, *bot;
2367 size_t top_x, bot_x;
2368
2369 if (old_mark_set) {
2370 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +00002371 * contains only the marked text, and turn the mark off. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002372 mark_order((const filestruct **)&top, &top_x,
2373 (const filestruct **)&bot, &bot_x, NULL);
2374 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002375 openfile->mark_set = FALSE;
2376 }
2377
2378 /* Start at the top of the file. */
2379 openfile->current = openfile->fileage;
2380 openfile->current_x = 0;
2381 openfile->placewewant = 0;
2382
2383 /* Keep moving to the next word (counting punctuation characters as
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002384 * part of a word, as "wc -w" does), without updating the screen,
2385 * until we reach the end of the file, incrementing the total word
2386 * count whenever we're on a word just before moving. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002387 while (openfile->current != openfile->filebot ||
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +00002388 openfile->current->data[openfile->current_x] != '\0') {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002389 if (do_next_word(TRUE, FALSE))
2390 words++;
2391 }
2392
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002393 /* Get the total line and character counts, as "wc -l" and "wc -c"
2394 * do, but get the latter in multibyte characters. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002395 if (old_mark_set) {
David Lawrence Ramsey78a81b22005-07-25 18:59:24 +00002396 lines = openfile->filebot->lineno -
2397 openfile->fileage->lineno + 1;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002398 chars = get_totsize(openfile->fileage, openfile->filebot);
2399
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002400 /* Unpartition the filestruct so that it contains all the text
2401 * again, and turn the mark back on. */
2402 unpartition_filestruct(&filepart);
2403 openfile->mark_set = TRUE;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002404 } else {
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002405 lines = openfile->filebot->lineno;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002406 chars = openfile->totsize;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002407 }
2408
2409 /* Restore where we were. */
2410 openfile->current = current_save;
2411 openfile->current_x = current_x_save;
2412 openfile->placewewant = pww_save;
2413
David Lawrence Ramsey72936852005-07-25 03:47:08 +00002414 /* Display the total word, line, and character counts on the
2415 * statusbar. */
David Lawrence Ramsey7b71f572005-10-06 20:46:11 +00002416 statusbar(_("%sWords: %lu Lines: %ld Chars: %lu"), old_mark_set ?
David Lawrence Ramsey815fb0a2005-08-05 19:38:11 +00002417 _("In Selection: ") : "", (unsigned long)words, (long)lines,
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002418 (unsigned long)chars);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002419}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002420#endif /* !NANO_TINY */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002421
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002422/* Get verbatim input. */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002423void do_verbatim_input(void)
2424{
2425 int *kbinput;
2426 size_t kbinput_len, i;
2427 char *output;
2428
David Lawrence Ramseyf451d6a2006-05-27 16:02:48 +00002429 /* TRANSLATORS: This is displayed when the next keystroke will be
2430 * inserted verbatim. */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002431 statusbar(_("Verbatim Input"));
2432
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002433 /* Read in all the verbatim characters. */
2434 kbinput = get_verbatim_kbinput(edit, &kbinput_len);
2435
David Lawrence Ramseya620e682006-05-27 18:19:03 +00002436 /* If constant cursor position display is on, make sure the current
2437 * cursor position will be properly displayed on the statusbar.
2438 * Otherwise, blank the statusbar. */
2439 if (ISSET(CONST_UPDATE))
2440 do_cursorpos(TRUE);
2441 else {
2442 blank_statusbar();
2443 wnoutrefresh(bottomwin);
2444 }
David Lawrence Ramsey6fb66892006-05-27 17:39:19 +00002445
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00002446 /* Display all the verbatim characters at once, not filtering out
2447 * control characters. */
2448 output = charalloc(kbinput_len + 1);
2449
2450 for (i = 0; i < kbinput_len; i++)
2451 output[i] = (char)kbinput[i];
2452 output[i] = '\0';
2453
2454 do_output(output, kbinput_len, TRUE);
2455
2456 free(output);
2457}