blob: 07dad2d7bc883f62703d329c82ee6c01cb5ba596 [file] [log] [blame]
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001/**************************************************************************
Benno Schulenberg514cd9a2016-08-29 17:10:49 +02002 * utils.c -- This file is part of GNU nano. *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003 * *
Chris Allegretta8a07a962009-12-02 03:36:22 +00004 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
Benno Schulenberg7a9f4a42014-04-30 20:18:26 +00005 * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. *
Benno Schulenberg406e5242016-08-29 15:14:18 +02006 * Copyright (C) 2016 Benno Schulenberg *
7 * *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +02008 * GNU nano is free software: you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published *
10 * by the Free Software Foundation, either version 3 of the License, *
11 * or (at your option) any later version. *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000012 * *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +020013 * GNU nano is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty *
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
16 * See the GNU General Public License for more details. *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000017 * *
18 * You should have received a copy of the GNU General Public License *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +020019 * along with this program. If not, see http://www.gnu.org/licenses/. *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000020 * *
21 **************************************************************************/
22
David Lawrence Ramsey034b9942005-12-08 02:47:10 +000023#include "proto.h"
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +000024
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000025#include <string.h>
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +000026#include <stdio.h>
27#include <unistd.h>
David Lawrence Ramsey65e6ecb2005-02-08 20:37:53 +000028#include <pwd.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000029#include <ctype.h>
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +000030#include <errno.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000031
David Lawrence Ramsey65e6ecb2005-02-08 20:37:53 +000032/* Return the user's home directory. We use $HOME, and if that fails,
David Lawrence Ramsey6335fb52007-01-01 05:15:32 +000033 * we fall back on the home directory of the effective user ID. */
David Lawrence Ramsey65e6ecb2005-02-08 20:37:53 +000034void get_homedir(void)
35{
36 if (homedir == NULL) {
37 const char *homenv = getenv("HOME");
38
Benno Schulenberg3a3b1762016-01-22 16:10:36 +000039 /* When HOME isn't set, or when we're root, get the home directory
40 * from the password file instead. */
41 if (homenv == NULL || geteuid() == 0) {
David Lawrence Ramsey65e6ecb2005-02-08 20:37:53 +000042 const struct passwd *userage = getpwuid(geteuid());
43
44 if (userage != NULL)
45 homenv = userage->pw_dir;
46 }
Benno Schulenberge06472a2015-06-20 08:21:35 +000047
48 /* Only set homedir if some home directory could be determined,
49 * otherwise keep homedir NULL. */
50 if (homenv != NULL && strcmp(homenv, "") != 0)
51 homedir = mallocstrcpy(NULL, homenv);
David Lawrence Ramsey65e6ecb2005-02-08 20:37:53 +000052 }
53}
54
Faissal Bensefiade95ca62016-10-20 09:44:29 +010055#ifdef ENABLE_LINENUMBERS
56/* Return the number of digits that the given integer n takes up. */
David Lawrence Ramseybd920b12016-12-09 11:36:01 -060057int digits(ssize_t n)
Faissal Bensefiade95ca62016-10-20 09:44:29 +010058{
59 if (n < 100000) {
60 if (n < 1000) {
61 if (n < 100)
62 return 2;
63 else
64 return 3;
65 } else {
66 if (n < 10000)
67 return 4;
68 else
69 return 5;
70 }
71 } else {
72 if (n < 10000000) {
73 if (n < 1000000)
74 return 6;
75 else
76 return 7;
77 }
78 else {
79 if (n < 100000000)
80 return 8;
81 else
82 return 9;
83 }
84 }
85}
86#endif
87
Benno Schulenbergea407652017-01-11 19:15:45 +010088/* Read an integer from str. If it parses okay, store it in *result
89 * and return TRUE; otherwise, return FALSE. */
90bool parse_num(const char *str, ssize_t *result)
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +000091{
92 char *first_error;
Benno Schulenbergea407652017-01-11 19:15:45 +010093 ssize_t value;
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +000094
Benno Schulenbergea407652017-01-11 19:15:45 +010095 /* The manual page for strtol() says this is required. */
Chris Allegrettab7a2dfb2013-01-13 08:37:54 +000096 errno = 0;
97
Benno Schulenbergea407652017-01-11 19:15:45 +010098 value = (ssize_t)strtol(str, &first_error, 10);
David Lawrence Ramsey32085a82004-12-08 04:00:26 +000099
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +0000100 if (errno == ERANGE || *str == '\0' || *first_error != '\0')
David Lawrence Ramseyc53ab2a2004-08-04 18:24:53 +0000101 return FALSE;
David Lawrence Ramsey32085a82004-12-08 04:00:26 +0000102
Benno Schulenbergea407652017-01-11 19:15:45 +0100103 *result = value;
David Lawrence Ramsey32085a82004-12-08 04:00:26 +0000104
David Lawrence Ramseyc53ab2a2004-08-04 18:24:53 +0000105 return TRUE;
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +0000106}
107
Benno Schulenberg7e3a9c32016-07-04 17:55:25 +0200108/* Read two numbers, separated by a comma, from str, and store them in
109 * *line and *column. Return FALSE on error, and TRUE otherwise. */
David Lawrence Ramsey2cf6d712005-06-28 06:25:34 +0000110bool parse_line_column(const char *str, ssize_t *line, ssize_t *column)
David Lawrence Ramseyb68c01b2005-05-16 23:23:15 +0000111{
Benno Schulenbergccfb1eb2016-07-04 20:51:11 +0200112 bool retval;
113 char *firstpart;
Rishabh Dave9c7940b2016-07-05 00:57:53 +0530114 const char *comma;
115
116 while (*str == ' ')
117 str++;
118
119 comma = strpbrk(str, "m,. /;");
David Lawrence Ramseyb68c01b2005-05-16 23:23:15 +0000120
Benno Schulenbergccfb1eb2016-07-04 20:51:11 +0200121 if (comma == NULL)
122 return parse_num(str, line);
David Lawrence Ramseyb68c01b2005-05-16 23:23:15 +0000123
Benno Schulenberg87b2df62016-12-26 11:45:38 +0100124 retval = parse_num(comma + 1, column);
David Lawrence Ramseyb68c01b2005-05-16 23:23:15 +0000125
Benno Schulenbergccfb1eb2016-07-04 20:51:11 +0200126 if (comma == str)
Benno Schulenberg87b2df62016-12-26 11:45:38 +0100127 return retval;
David Lawrence Ramseyb68c01b2005-05-16 23:23:15 +0000128
Benno Schulenberg62eeda32016-07-11 20:39:53 +0200129 firstpart = mallocstrcpy(NULL, str);
Benno Schulenbergccfb1eb2016-07-04 20:51:11 +0200130 firstpart[comma - str] = '\0';
David Lawrence Ramseyc5659d32005-05-17 00:25:50 +0000131
Benno Schulenberge8c7cf22017-01-17 14:17:42 +0100132 retval = parse_num(firstpart, line) && retval;
Benno Schulenberg87b2df62016-12-26 11:45:38 +0100133
Benno Schulenbergccfb1eb2016-07-04 20:51:11 +0200134 free(firstpart);
David Lawrence Ramseyc5659d32005-05-17 00:25:50 +0000135
136 return retval;
David Lawrence Ramseyb68c01b2005-05-16 23:23:15 +0000137}
138
Benno Schulenberg8c7e4f52016-12-16 20:34:38 +0100139/* Reduce the memory allocation of a string to what is needed. */
140void snuggly_fit(char **str)
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000141{
David Lawrence Ramsey6a0d5b82005-06-13 14:00:22 +0000142 if (*str != NULL)
143 *str = charealloc(*str, strlen(*str) + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000144}
145
146/* Null a string at a certain index and align it. */
147void null_at(char **data, size_t index)
148{
Chris Allegrettae1e0fd62003-04-15 01:15:09 +0000149 *data = charealloc(*data, index + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000150 (*data)[index] = '\0';
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000151}
152
153/* For non-null-terminated lines. A line, by definition, shouldn't
Chris Allegretta6df90f52002-07-19 01:08:59 +0000154 * normally have newlines in it, so encode its nulls as newlines. */
155void unsunder(char *str, size_t true_len)
156{
David Lawrence Ramseya7c93642004-02-25 03:19:29 +0000157 for (; true_len > 0; true_len--, str++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +0000158 if (*str == '\0')
159 *str = '\n';
David Lawrence Ramseya7c93642004-02-25 03:19:29 +0000160 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000161}
162
163/* For non-null-terminated lines. A line, by definition, shouldn't
David Lawrence Ramsey9d4b8fb2006-11-27 05:49:32 +0000164 * normally have newlines in it, so decode its newlines as nulls. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000165void sunder(char *str)
166{
David Lawrence Ramseya7c93642004-02-25 03:19:29 +0000167 for (; *str != '\0'; str++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +0000168 if (*str == '\n')
169 *str = '\0';
David Lawrence Ramseya7c93642004-02-25 03:19:29 +0000170 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000171}
172
David Lawrence Ramseyd15c92d2005-11-17 18:58:56 +0000173/* These functions, ngetline() (originally getline()) and ngetdelim()
174 * (originally getdelim()), were adapted from GNU mailutils 0.5
175 * (mailbox/getline.c). Here is the notice from that file, after
David Lawrence Ramsey13b61152005-11-30 18:57:05 +0000176 * converting to the GPL via LGPL clause 3, and with the Free Software
David Lawrence Ramsey84c68452007-08-10 22:07:14 +0000177 * Foundation's address and the copyright years updated:
David Lawrence Ramsey3f7c8c52005-11-14 22:20:35 +0000178 *
179 * GNU Mailutils -- a suite of utilities for electronic mail
David Lawrence Ramseyd8a1d372007-10-11 05:01:32 +0000180 * Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
181 * Free Software Foundation, Inc.
David Lawrence Ramsey3f7c8c52005-11-14 22:20:35 +0000182 *
183 * This library is free software; you can redistribute it and/or
David Lawrence Ramseya1064d42005-11-14 23:02:03 +0000184 * modify it under the terms of the GNU General Public License as
David Lawrence Ramseyd0035b42007-08-11 05:17:36 +0000185 * published by the Free Software Foundation; either version 3 of the
David Lawrence Ramseya1064d42005-11-14 23:02:03 +0000186 * License, or (at your option) any later version.
David Lawrence Ramsey3f7c8c52005-11-14 22:20:35 +0000187 *
188 * This library is distributed in the hope that it will be useful,
189 * but WITHOUT ANY WARRANTY; without even the implied warranty of
190 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
David Lawrence Ramseya1064d42005-11-14 23:02:03 +0000191 * General Public License for more details.
David Lawrence Ramsey3f7c8c52005-11-14 22:20:35 +0000192 *
David Lawrence Ramseya1064d42005-11-14 23:02:03 +0000193 * You should have received a copy of the GNU General Public License
194 * along with this library; if not, write to the Free Software
David Lawrence Ramsey13b61152005-11-30 18:57:05 +0000195 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
196 * 02110-1301, USA. */
David Lawrence Ramsey3f7c8c52005-11-14 22:20:35 +0000197
Benno Schulenbergeea09082014-04-13 20:50:20 +0000198#ifndef DISABLE_NANORC
David Lawrence Ramseya27bd652004-08-17 05:23:38 +0000199
200#ifndef HAVE_GETDELIM
David Lawrence Ramsey3f7c8c52005-11-14 22:20:35 +0000201/* This function is equivalent to getdelim(). */
David Lawrence Ramseya27bd652004-08-17 05:23:38 +0000202ssize_t ngetdelim(char **lineptr, size_t *n, int delim, FILE *stream)
203{
David Lawrence Ramseya27bd652004-08-17 05:23:38 +0000204 size_t indx = 0;
205 int c;
206
207 /* Sanity checks. */
David Lawrence Ramsey497a9a22006-06-04 00:15:56 +0000208 if (lineptr == NULL || n == NULL || stream == NULL ||
209 fileno(stream) == -1) {
David Lawrence Ramsey76f94852006-01-09 03:23:29 +0000210 errno = EINVAL;
211 return -1;
212 }
David Lawrence Ramseya27bd652004-08-17 05:23:38 +0000213
214 /* Allocate the line the first time. */
215 if (*lineptr == NULL) {
David Lawrence Ramsey5b2f17e2005-04-19 21:47:01 +0000216 *n = MAX_BUF_SIZE;
David Lawrence Ramsey273c1132007-08-10 17:03:29 +0000217 *lineptr = charalloc(*n);
David Lawrence Ramseya27bd652004-08-17 05:23:38 +0000218 }
219
220 while ((c = getc(stream)) != EOF) {
221 /* Check if more memory is needed. */
222 if (indx >= *n) {
David Lawrence Ramsey5b2f17e2005-04-19 21:47:01 +0000223 *n += MAX_BUF_SIZE;
David Lawrence Ramsey273c1132007-08-10 17:03:29 +0000224 *lineptr = charealloc(*lineptr, *n);
David Lawrence Ramseya27bd652004-08-17 05:23:38 +0000225 }
226
David Lawrence Ramsey8dec7832005-11-17 04:13:01 +0000227 /* Put the result in the line. */
David Lawrence Ramseya27bd652004-08-17 05:23:38 +0000228 (*lineptr)[indx++] = (char)c;
229
230 /* Bail out. */
231 if (c == delim)
232 break;
233 }
234
235 /* Make room for the null character. */
236 if (indx >= *n) {
David Lawrence Ramsey5b2f17e2005-04-19 21:47:01 +0000237 *n += MAX_BUF_SIZE;
David Lawrence Ramsey273c1132007-08-10 17:03:29 +0000238 *lineptr = charealloc(*lineptr, *n);
David Lawrence Ramseya27bd652004-08-17 05:23:38 +0000239 }
240
David Lawrence Ramseye54f1c42006-10-29 21:14:53 +0000241 /* Null-terminate the buffer. */
David Lawrence Ramseyc08368b2004-08-17 19:20:05 +0000242 null_at(lineptr, indx++);
David Lawrence Ramsey35fb55a2004-08-17 19:28:54 +0000243 *n = indx;
David Lawrence Ramseya27bd652004-08-17 05:23:38 +0000244
David Lawrence Ramsey8dec7832005-11-17 04:13:01 +0000245 /* The last line may not have the delimiter. We have to return what
246 * we got, and the error will be seen on the next iteration. */
David Lawrence Ramseya27bd652004-08-17 05:23:38 +0000247 return (c == EOF && (indx - 1) == 0) ? -1 : indx - 1;
248}
249#endif
Chris Allegrettaecc245c2009-02-01 00:04:42 +0000250
251#ifndef HAVE_GETLINE
252/* This function is equivalent to getline(). */
253ssize_t ngetline(char **lineptr, size_t *n, FILE *stream)
254{
255 return getdelim(lineptr, n, '\n', stream);
256}
257#endif
Benno Schulenbergeea09082014-04-13 20:50:20 +0000258#endif /* !DISABLE_NANORC */
David Lawrence Ramseya27bd652004-08-17 05:23:38 +0000259
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000260#ifdef HAVE_REGEX_H
Benno Schulenberg8f615112014-04-14 09:57:06 +0000261/* Fix the regex if we're on platforms which require an adjustment
262 * from GNU-style to BSD-style word boundaries. */
Benno Schulenberg1de337d2014-06-04 16:02:51 +0000263const char *fixbounds(const char *r)
264{
Chris Allegretta6b83e522008-08-30 05:16:20 +0000265#ifndef GNU_WORDBOUNDS
266 int i, j = 0;
267 char *r2 = charalloc(strlen(r) * 5);
268 char *r3;
269
270#ifdef DEBUG
271 fprintf(stderr, "fixbounds(): Start string = \"%s\"\n", r);
272#endif
273
274 for (i = 0; i < strlen(r); i++) {
Benno Schulenberg1de337d2014-06-04 16:02:51 +0000275 if (r[i] != '\0' && r[i] == '\\' && (r[i + 1] == '>' || r[i + 1] == '<')) {
276 strcpy(&r2[j], "[[:");
277 r2[j + 3] = r[i + 1];
278 strcpy(&r2[j + 4], ":]]");
279 i++;
280 j += 6;
281 } else
282 r2[j] = r[i];
283 j++;
Chris Allegretta6b83e522008-08-30 05:16:20 +0000284 }
285 r2[j] = '\0';
286 r3 = mallocstrcpy(NULL, r2);
287 free(r2);
288#ifdef DEBUG
289 fprintf(stderr, "fixbounds(): Ending string = \"%s\"\n", r3);
290#endif
291 return (const char *) r3;
Benno Schulenbergaf708842015-04-25 14:52:58 +0000292#endif /* !GNU_WORDBOUNDS */
Chris Allegretta6b83e522008-08-30 05:16:20 +0000293
294 return r;
295}
Benno Schulenbergaf708842015-04-25 14:52:58 +0000296#endif /* HAVE_REGEX_H */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000297
David Lawrence Ramseycf9c34a2005-11-16 05:59:06 +0000298#ifndef DISABLE_SPELLER
Benno Schulenbergcc0a3d82016-05-02 22:20:19 +0200299/* Is the word starting at the given position in buf and of the given length
300 * a separate word? That is: is it not part of a longer word?*/
301bool is_separate_word(size_t position, size_t length, const char *buf)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000302{
Benno Schulenberg8db21b62016-12-26 10:27:42 +0100303 char before[mb_cur_max()], after[mb_cur_max()];
Benno Schulenbergcc0a3d82016-05-02 22:20:19 +0200304 size_t word_end = position + length;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000305
Benno Schulenbergcc0a3d82016-05-02 22:20:19 +0200306 /* Get the characters before and after the word, if any. */
307 parse_mbchar(buf + move_mbleft(buf, position), before, NULL);
308 parse_mbchar(buf + word_end, after, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000309
Benno Schulenberg20058a12016-08-02 22:09:22 +0200310 /* If the word starts at the beginning of the line OR the character before
311 * the word isn't a letter, and if the word ends at the end of the line OR
312 * the character after the word isn't a letter, we have a whole word. */
Benno Schulenberg8db21b62016-12-26 10:27:42 +0100313 return ((position == 0 || !is_alpha_mbchar(before)) &&
314 (buf[word_end] == '\0' || !is_alpha_mbchar(after)));
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000315}
David Lawrence Ramseycf9c34a2005-11-16 05:59:06 +0000316#endif /* !DISABLE_SPELLER */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +0000317
Benno Schulenberg64aa8752017-01-26 16:24:18 +0100318/* Return the position of the needle in the haystack, or NULL if not found.
319 * When searching backwards, we will find the last match that starts no later
320 * than the given start; otherwise, we find the first match starting no earlier
321 * than start. If we are doing a regexp search, and we find a match, we fill
322 * in the global variable regmatches with at most 9 subexpression matches. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000323const char *strstrwrapper(const char *haystack, const char *needle,
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000324 const char *start)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000325{
Chris Allegretta805c26d2000-09-06 13:39:17 +0000326#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000327 if (ISSET(USE_REGEXP)) {
David Lawrence Ramseyf3ecffd2005-06-16 18:48:30 +0000328 if (ISSET(BACKWARDS_SEARCH)) {
Benno Schulenberg64aa8752017-01-26 16:24:18 +0100329 size_t last_find, ceiling, far_end;
330 size_t floor = 0, next_rung = 0;
331 /* The start of the search range, and the next start. */
Chris Allegretta8dbfb5c2002-01-28 15:56:15 +0000332
Benno Schulenberg64aa8752017-01-26 16:24:18 +0100333 if (regexec(&search_regexp, haystack, 1, regmatches, 0) != 0)
334 return NULL;
335
336 far_end = strlen(haystack);
337 ceiling = start - haystack;
338 last_find = regmatches[0].rm_so;
339
340 /* A result beyond the search range also means: no match. */
341 if (last_find > ceiling)
342 return NULL;
343
344 /* Move the start-of-range forward until there is no more match;
345 * then the last match found is the first match backwards. */
346 while (regmatches[0].rm_so <= ceiling) {
347 floor = next_rung;
348 last_find = regmatches[0].rm_so;
349 /* If this is the last possible match, don't try to advance. */
350 if (last_find == ceiling)
351 break;
352 next_rung = move_mbright(haystack, last_find);
353 regmatches[0].rm_so = next_rung;
354 regmatches[0].rm_eo = far_end;
355 if (regexec(&search_regexp, haystack, 1, regmatches,
356 REG_STARTEND) != 0)
357 break;
Chris Allegrettae4933a32001-06-13 02:35:44 +0000358 }
Chris Allegretta9090f2e2003-01-26 04:45:05 +0000359
Benno Schulenberg64aa8752017-01-26 16:24:18 +0100360 /* Find the last match again, to get possible submatches. */
361 regmatches[0].rm_so = floor;
362 regmatches[0].rm_eo = far_end;
363 if (regexec(&search_regexp, haystack, 10, regmatches,
364 REG_STARTEND) != 0)
365 statusline(ALERT, "BAD: failed to refind the match!");
366
367 return haystack + regmatches[0].rm_so;
Chris Allegretta8dbfb5c2002-01-28 15:56:15 +0000368 }
Benno Schulenberg64aa8752017-01-26 16:24:18 +0100369
370 /* Do a forward regex search from the starting point. */
371 regmatches[0].rm_so = start - haystack;
372 regmatches[0].rm_eo = strlen(haystack);
373 if (regexec(&search_regexp, haystack, 10, regmatches,
374 REG_STARTEND) != 0)
375 return NULL;
376 else
377 return haystack + regmatches[0].rm_so;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000378 }
Chris Allegretta9090f2e2003-01-26 04:45:05 +0000379#endif /* HAVE_REGEX_H */
Chris Allegrettae10f3892001-10-02 03:54:40 +0000380 if (ISSET(CASE_SENSITIVE)) {
David Lawrence Ramseyf3ecffd2005-06-16 18:48:30 +0000381 if (ISSET(BACKWARDS_SEARCH))
David Lawrence Ramsey1044d742004-02-24 20:41:39 +0000382 return revstrstr(haystack, needle, start);
Chris Allegretta5f36c372001-07-16 00:48:53 +0000383 else
David Lawrence Ramsey2a464cb2004-03-07 21:16:18 +0000384 return strstr(start, needle);
Benno Schulenberg08cd1972016-09-08 21:00:51 +0200385 } else if (ISSET(BACKWARDS_SEARCH))
David Lawrence Ramsey345260c2005-01-24 01:14:17 +0000386 return mbrevstrcasestr(haystack, needle, start);
Benno Schulenberg08cd1972016-09-08 21:00:51 +0200387
David Lawrence Ramsey42abfe02005-01-22 18:24:16 +0000388 return mbstrcasestr(start, needle);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000389}
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000390
David Lawrence Ramseyf70f67b2006-06-03 17:31:52 +0000391/* This is a wrapper for the perror() function. The wrapper temporarily
392 * leaves curses mode, calls perror() (which writes to stderr), and then
393 * reenters curses mode, updating the screen in the process. Note that
394 * nperror() causes the window to flicker once. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000395void nperror(const char *s)
396{
David Lawrence Ramseyf70f67b2006-06-03 17:31:52 +0000397 endwin();
398 perror(s);
399 doupdate();
Chris Allegretta77777d42002-03-29 16:31:29 +0000400}
401
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000402/* This is a wrapper for the malloc() function that properly handles
403 * things when we run out of memory. Thanks, BG, many people have been
404 * asking for this... */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000405void *nmalloc(size_t howmuch)
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000406{
Chris Allegretta7662c862003-01-13 01:35:15 +0000407 void *r = malloc(howmuch);
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000408
Chris Allegretta7662c862003-01-13 01:35:15 +0000409 if (r == NULL && howmuch != 0)
410 die(_("nano is out of memory!"));
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000411
Chris Allegretta6df90f52002-07-19 01:08:59 +0000412 return r;
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000413}
414
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000415/* This is a wrapper for the realloc() function that properly handles
416 * things when we run out of memory. */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000417void *nrealloc(void *ptr, size_t howmuch)
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000418{
Chris Allegretta7662c862003-01-13 01:35:15 +0000419 void *r = realloc(ptr, howmuch);
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000420
Chris Allegretta7662c862003-01-13 01:35:15 +0000421 if (r == NULL && howmuch != 0)
422 die(_("nano is out of memory!"));
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000423
424 return r;
425}
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000426
Benno Schulenberg06c80622016-07-11 20:10:10 +0200427/* Allocate and copy the first n characters of the given src string, after
428 * freeing the destination. Usage: "dest = mallocstrncpy(dest, src, n);". */
David Lawrence Ramsey4a1fc552004-11-02 15:18:30 +0000429char *mallocstrncpy(char *dest, const char *src, size_t n)
Chris Allegretta31925e42000-11-02 04:40:39 +0000430{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000431 if (src == NULL)
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000432 src = "";
433
434 if (src != dest)
435 free(dest);
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000436
David Lawrence Ramsey4a1fc552004-11-02 15:18:30 +0000437 dest = charalloc(n);
David Lawrence Ramsey16799ba2005-06-21 22:32:50 +0000438 strncpy(dest, src, n);
Chris Allegretta31925e42000-11-02 04:40:39 +0000439
440 return dest;
441}
442
Benno Schulenberg06c80622016-07-11 20:10:10 +0200443/* Free the dest string and return a malloc'ed copy of src. Should be used as:
David Lawrence Ramsey4a1fc552004-11-02 15:18:30 +0000444 * "dest = mallocstrcpy(dest, src);". */
445char *mallocstrcpy(char *dest, const char *src)
446{
Benno Schulenbergf2da4662015-12-04 21:11:10 +0000447 return mallocstrncpy(dest, src, (src == NULL) ? 1 : strlen(src) + 1);
David Lawrence Ramsey4a1fc552004-11-02 15:18:30 +0000448}
449
Benno Schulenberg8b28de12016-07-13 15:04:40 +0200450/* Free the string at dest and return the string at src. */
451char *free_and_assign(char *dest, char *src)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +0000452{
453 free(dest);
454 return src;
455}
456
David Lawrence Ramsey2b9d6a02005-11-01 17:45:31 +0000457/* nano scrolls horizontally within a line in chunks. Return the column
458 * number of the first character displayed in the edit window when the
459 * cursor is at the given column. Note that (0 <= column -
460 * get_page_start(column) < COLS). */
461size_t get_page_start(size_t column)
462{
Faissal Bensefiade95ca62016-10-20 09:44:29 +0100463 if (column == 0 || column < editwincols - 1)
David Lawrence Ramsey2b9d6a02005-11-01 17:45:31 +0000464 return 0;
Faissal Bensefiade95ca62016-10-20 09:44:29 +0100465 else if (editwincols > 8)
466 return column - 7 - (column - 7) % (editwincols - 8);
David Lawrence Ramsey2b9d6a02005-11-01 17:45:31 +0000467 else
Faissal Bensefiade95ca62016-10-20 09:44:29 +0100468 return column - (editwincols - 2);
David Lawrence Ramsey2b9d6a02005-11-01 17:45:31 +0000469}
470
David Lawrence Ramseyb159f942006-07-28 17:06:27 +0000471/* Return the placewewant associated with current_x, i.e. the zero-based
Benno Schulenbergdbe39902016-04-10 17:42:01 +0200472 * column position of the cursor. */
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000473size_t xplustabs(void)
474{
Benno Schulenbergdbe39902016-04-10 17:42:01 +0200475 return strnlenpt(openfile->current->data, openfile->current_x);
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000476}
477
Benno Schulenbergfbd817f2016-05-28 13:23:41 +0200478/* Return the index in text of the character that (when displayed) will
479 * not overshoot the given column. */
480size_t actual_x(const char *text, size_t column)
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000481{
Benno Schulenbergfbd817f2016-05-28 13:23:41 +0200482 size_t index = 0;
483 /* The index in text, returned. */
484 size_t width = 0;
485 /* The screen display width to text[index], in columns. */
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000486
Benno Schulenbergfbd817f2016-05-28 13:23:41 +0200487 while (*text != '\0') {
488 int charlen = parse_mbchar(text, NULL, &width);
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000489
Benno Schulenbergfbd817f2016-05-28 13:23:41 +0200490 if (width > column)
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000491 break;
492
Benno Schulenbergfbd817f2016-05-28 13:23:41 +0200493 index += charlen;
494 text += charlen;
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000495 }
496
Benno Schulenbergfbd817f2016-05-28 13:23:41 +0200497 return index;
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000498}
499
Benno Schulenberg981b4142016-04-24 22:02:48 +0200500/* A strnlen() with tabs and multicolumn characters factored in:
501 * how many columns wide are the first maxlen bytes of text? */
502size_t strnlenpt(const char *text, size_t maxlen)
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000503{
Benno Schulenberg981b4142016-04-24 22:02:48 +0200504 size_t width = 0;
505 /* The screen display width to text[maxlen]. */
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000506
507 if (maxlen == 0)
508 return 0;
509
Benno Schulenberg981b4142016-04-24 22:02:48 +0200510 while (*text != '\0') {
511 int charlen = parse_mbchar(text, NULL, &width);
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000512
Benno Schulenberg981b4142016-04-24 22:02:48 +0200513 if (maxlen <= charlen)
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000514 break;
515
Benno Schulenberg981b4142016-04-24 22:02:48 +0200516 maxlen -= charlen;
Benno Schulenbergfbd817f2016-05-28 13:23:41 +0200517 text += charlen;
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000518 }
519
Benno Schulenberg981b4142016-04-24 22:02:48 +0200520 return width;
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000521}
522
Benno Schulenberg981b4142016-04-24 22:02:48 +0200523/* A strlen() with tabs and multicolumn characters factored in:
524 * how many columns wide is text? */
525size_t strlenpt(const char *text)
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000526{
Benno Schulenberg981b4142016-04-24 22:02:48 +0200527 return strnlenpt(text, (size_t)-1);
David Lawrence Ramsey81c4e182005-10-31 23:07:58 +0000528}
529
David Lawrence Ramsey02517e02004-09-05 21:40:31 +0000530/* Append a new magicline to filebot. */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000531void new_magicline(void)
532{
David Lawrence Ramsey17f5c052017-02-09 16:00:07 -0600533 openfile->filebot->next = make_new_node(openfile->filebot);
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000534 openfile->filebot->next->data = mallocstrcpy(NULL, "");
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000535 openfile->filebot = openfile->filebot->next;
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000536 openfile->totsize++;
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000537}
Chris Allegretta04d848e2000-11-05 17:54:41 +0000538
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000539#ifndef NANO_TINY
David Lawrence Ramsey8ae06a82004-11-07 01:26:39 +0000540/* Remove the magicline from filebot, if there is one and it isn't the
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000541 * only line in the file. Assume that edittop and current are not at
542 * filebot. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000543void remove_magicline(void)
544{
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000545 if (openfile->filebot->data[0] == '\0' &&
Benno Schulenberg95f417f2016-06-14 11:06:04 +0200546 openfile->filebot != openfile->fileage) {
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000547 openfile->filebot = openfile->filebot->prev;
548 free_filestruct(openfile->filebot->next);
549 openfile->filebot->next = NULL;
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000550 openfile->totsize--;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000551 }
552}
553
David Lawrence Ramsey93c84052004-11-23 04:08:28 +0000554/* Set top_x and bot_x to the top and bottom x-coordinates of the mark,
555 * respectively, based on the locations of top and bot. If
David Lawrence Ramsey3305c112007-08-07 18:37:39 +0000556 * right_side_up isn't NULL, set it to TRUE if the mark begins with
David Lawrence Ramsey5128de82005-07-12 17:40:16 +0000557 * (mark_begin, mark_begin_x) and ends with (current, current_x), or
David Lawrence Ramsey93c84052004-11-23 04:08:28 +0000558 * FALSE otherwise. */
559void mark_order(const filestruct **top, size_t *top_x, const filestruct
560 **bot, size_t *bot_x, bool *right_side_up)
561{
David Lawrence Ramsey5128de82005-07-12 17:40:16 +0000562 if ((openfile->current->lineno == openfile->mark_begin->lineno &&
Benno Schulenberg95f417f2016-06-14 11:06:04 +0200563 openfile->current_x > openfile->mark_begin_x) ||
564 openfile->current->lineno > openfile->mark_begin->lineno) {
David Lawrence Ramsey5128de82005-07-12 17:40:16 +0000565 *top = openfile->mark_begin;
566 *top_x = openfile->mark_begin_x;
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000567 *bot = openfile->current;
568 *bot_x = openfile->current_x;
David Lawrence Ramsey93c84052004-11-23 04:08:28 +0000569 if (right_side_up != NULL)
570 *right_side_up = TRUE;
571 } else {
David Lawrence Ramsey5128de82005-07-12 17:40:16 +0000572 *bot = openfile->mark_begin;
573 *bot_x = openfile->mark_begin_x;
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000574 *top = openfile->current;
575 *top_x = openfile->current_x;
David Lawrence Ramsey93c84052004-11-23 04:08:28 +0000576 if (right_side_up != NULL)
577 *right_side_up = FALSE;
578 }
579}
David Lawrence Ramsey93c84052004-11-23 04:08:28 +0000580
Benno Schulenbergfe9cf6f2016-05-08 10:41:53 +0200581/* Given a line number, return a pointer to the corresponding struct. */
Chris Allegretta14c86202008-08-03 04:48:05 +0000582filestruct *fsfromline(ssize_t lineno)
583{
584 filestruct *f = openfile->current;
585
586 if (lineno <= openfile->current->lineno)
Benno Schulenbergfe9cf6f2016-05-08 10:41:53 +0200587 while (f->lineno != lineno && f->prev != NULL)
588 f = f->prev;
Chris Allegretta14c86202008-08-03 04:48:05 +0000589 else
Benno Schulenbergfe9cf6f2016-05-08 10:41:53 +0200590 while (f->lineno != lineno && f->next != NULL)
591 f = f->next;
Chris Allegretta14c86202008-08-03 04:48:05 +0000592
Benno Schulenberg06b449b2016-05-08 10:51:40 +0200593 if (f->lineno != lineno) {
David Lawrence Ramsey84d6f1a2016-12-08 13:30:59 -0600594 statusline(ALERT, _("Internal error: can't match line %ld. "
595 "Please save your work."), (long)lineno);
Benno Schulenbergfe9cf6f2016-05-08 10:41:53 +0200596 return NULL;
Benno Schulenberg06b449b2016-05-08 10:51:40 +0200597 }
Benno Schulenbergfe9cf6f2016-05-08 10:41:53 +0200598
Chris Allegretta14c86202008-08-03 04:48:05 +0000599 return f;
600}
Benno Schulenberg9fa95a32016-12-15 13:04:52 +0100601#endif /* !NANO_TINY */
602
603/* Count the number of characters from begin to end, and return it. */
604size_t get_totsize(const filestruct *begin, const filestruct *end)
605{
606 const filestruct *line;
607 size_t totsize = 0;
608
609 /* Sum the number of characters (plus a newline) in each line. */
610 for (line = begin; line != end->next; line = line->next)
611 totsize += mbstrlen(line->data) + 1;
612
613 /* The last line of a file doesn't have a newline -- otherwise it
614 * wouldn't be the last line -- so subtract 1 when at EOF. */
615 if (line == NULL)
616 totsize--;
617
618 return totsize;
619}
Chris Allegretta14c86202008-08-03 04:48:05 +0000620
Chris Allegretta599c5592008-08-05 01:35:42 +0000621#ifdef DEBUG
622/* Dump the filestruct inptr to stderr. */
623void dump_filestruct(const filestruct *inptr)
624{
625 if (inptr == openfile->fileage)
626 fprintf(stderr, "Dumping file buffer to stderr...\n");
627 else if (inptr == cutbuffer)
628 fprintf(stderr, "Dumping cutbuffer to stderr...\n");
629 else
630 fprintf(stderr, "Dumping a buffer to stderr...\n");
631
632 while (inptr != NULL) {
633 fprintf(stderr, "(%ld) %s\n", (long)inptr->lineno, inptr->data);
634 inptr = inptr->next;
635 }
636}
Chris Allegretta14c86202008-08-03 04:48:05 +0000637
David Lawrence Ramsey00cc5652005-11-02 15:44:01 +0000638/* Dump the current buffer's filestruct to stderr in reverse. */
639void dump_filestruct_reverse(void)
640{
641 const filestruct *fileptr = openfile->filebot;
642
643 while (fileptr != NULL) {
644 fprintf(stderr, "(%ld) %s\n", (long)fileptr->lineno,
645 fileptr->data);
646 fileptr = fileptr->prev;
647 }
648}
649#endif /* DEBUG */