utils.c 8.78 KB
Newer Older
Chris Allegretta's avatar
Chris Allegretta committed
1
/* $Id$ */
Chris Allegretta's avatar
Chris Allegretta committed
2
3
4
/**************************************************************************
 *   utils.c                                                              *
 *                                                                        *
5
 *   Copyright (C) 1999-2002 Chris Allegretta                             *
Chris Allegretta's avatar
Chris Allegretta committed
6
7
 *   This program is free software; you can redistribute it and/or modify *
 *   it under the terms of the GNU General Public License as published by *
8
 *   the Free Software Foundation; either version 2, or (at your option)  *
Chris Allegretta's avatar
Chris Allegretta committed
9
10
11
12
13
14
15
16
17
18
19
20
21
 *   any later version.                                                   *
 *                                                                        *
 *   This program is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of       *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
 *   GNU General Public License for more details.                         *
 *                                                                        *
 *   You should have received a copy of the GNU General Public License    *
 *   along with this program; if not, write to the Free Software          *
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
 *                                                                        *
 **************************************************************************/

22
#include <stdio.h>
23
#include <unistd.h>
Chris Allegretta's avatar
Chris Allegretta committed
24
25
26
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
Chris Allegretta's avatar
Chris Allegretta committed
27
#include <assert.h>
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
28
#include "config.h"
Chris Allegretta's avatar
Chris Allegretta committed
29
#include "proto.h"
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
30
#include "nano.h"
Chris Allegretta's avatar
Chris Allegretta committed
31

32
#ifdef ENABLE_NLS
Chris Allegretta's avatar
Chris Allegretta committed
33
34
35
36
37
38
#include <libintl.h>
#define _(string) gettext(string)
#else
#define _(string) (string)
#endif

Chris Allegretta's avatar
Chris Allegretta committed
39
40
41
42
43
44
45
46
int is_cntrl_char(int c)
{
    if (iscntrl(c) || ((c & 127) != 127 && iscntrl(c & 127)))
	return 1;
    else
	return 0;
}

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
int num_of_digits(int n)
{
    int i = 1;

    if (n < 0)
	n = 0 - n;

    while (n > 10) {
	n /= 10;
	i++;
    }

    return i;
}

Chris Allegretta's avatar
Chris Allegretta committed
62
63
/* Fix the memory allocation for a string. */
void align(char **strp)
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
64
{
Chris Allegretta's avatar
Chris Allegretta committed
65
66
    assert(strp != NULL);
    *strp = nrealloc(*strp, strlen(*strp) + 1);
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
67
68
}

Chris Allegretta's avatar
Chris Allegretta committed
69
70
/* Null a string at a certain index and align it. */
void null_at(char **data, size_t index)
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
71
{
Chris Allegretta's avatar
Chris Allegretta committed
72
73
74
    assert(data != NULL);
    *data = (char *)nrealloc(*data, sizeof(char) * (index + 1));
    (*data)[index] = '\0';
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
75
76
}

Chris Allegretta's avatar
Chris Allegretta committed
77
78
79
/* For non-null-terminated lines.  A line, by definition, shouldn't
 * normally have newlines in it, so encode its nulls as newlines. */
void unsunder(char *str, size_t true_len)
Chris Allegretta's avatar
Chris Allegretta committed
80
{
Chris Allegretta's avatar
Chris Allegretta committed
81
82
83
84
85
    assert(str != NULL);
    for(; true_len > 0; true_len--, str++)
	if (*str == '\0')
	    *str = '\n';
}
Chris Allegretta's avatar
Chris Allegretta committed
86

Chris Allegretta's avatar
Chris Allegretta committed
87
88
89
90
91
92
93
94
/* For non-null-terminated lines.  A line, by definition, shouldn't
 * normally have newlines in it, so decode its newlines into nulls. */
void sunder(char *str)
{
    assert(str != NULL);
    for(; *str != '\0'; str++)
	if (*str == '\n')
	    *str = '\0';
Chris Allegretta's avatar
Chris Allegretta committed
95
96
}

97
98
/* None of this is needed if we're using NANO_SMALL! */
#ifndef NANO_SMALL
Chris Allegretta's avatar
Chris Allegretta committed
99
100
static const char *revstrstr(const char *haystack, const char *needle,
	const char *rev_start)
Chris Allegretta's avatar
Chris Allegretta committed
101
{
Chris Allegretta's avatar
Chris Allegretta committed
102
103
    for(; rev_start >= haystack ; rev_start--) {
	const char *r, *q;
Chris Allegretta's avatar
Chris Allegretta committed
104

Chris Allegretta's avatar
Chris Allegretta committed
105
	for (r = rev_start, q = needle ; *q == *r && *q != '\0'; r++, q++)
Chris Allegretta's avatar
Chris Allegretta committed
106
107
	    ;
	if (*q == '\0')
Chris Allegretta's avatar
Chris Allegretta committed
108
	    return rev_start;
Chris Allegretta's avatar
Chris Allegretta committed
109
    }
Chris Allegretta's avatar
Chris Allegretta committed
110
    return NULL;
Chris Allegretta's avatar
Chris Allegretta committed
111
112
}

Chris Allegretta's avatar
Chris Allegretta committed
113
114
static const char *revstristr(const char *haystack, const char *needle,
	const char *rev_start)
Chris Allegretta's avatar
Chris Allegretta committed
115
{
Chris Allegretta's avatar
Chris Allegretta committed
116
117
    for (; rev_start >= haystack; rev_start--) {
	const char *r = rev_start, *q = needle;
Chris Allegretta's avatar
Chris Allegretta committed
118

Chris Allegretta's avatar
Chris Allegretta committed
119
	for (; (tolower(*q) == tolower(*r)) && (*q != '\0') ; r++, q++)
Chris Allegretta's avatar
Chris Allegretta committed
120
121
	    ;
	if (*q == '\0')
Chris Allegretta's avatar
Chris Allegretta committed
122
	    return rev_start;
Chris Allegretta's avatar
Chris Allegretta committed
123
    }
Chris Allegretta's avatar
Chris Allegretta committed
124
    return NULL;
Chris Allegretta's avatar
Chris Allegretta committed
125
}
Chris Allegretta's avatar
Chris Allegretta committed
126
#endif /* !NANO_SMALL */
Chris Allegretta's avatar
Chris Allegretta committed
127

128
/* This is now mutt's version (called mutt_stristr) because it doesn't
Chris Allegretta's avatar
typo    
Chris Allegretta committed
129
   use memory allocation to do a simple search (yuck). */
Chris Allegretta's avatar
Chris Allegretta committed
130
const char *stristr(const char *haystack, const char *needle)
Chris Allegretta's avatar
Chris Allegretta committed
131
{
132
    const char *p, *q;
Chris Allegretta's avatar
Chris Allegretta committed
133

134
    if (!haystack)
Chris Allegretta's avatar
Chris Allegretta committed
135
	return NULL;
136
137
138
    if (!needle)  
	return (haystack);
    
Chris Allegretta's avatar
Chris Allegretta committed
139
    while (*(p = haystack)) {
Chris Allegretta's avatar
Chris Allegretta committed
140
	for (q = needle; *p && *q && tolower(*p) == tolower(*q); p++, q++)
141
142
	    ;
	if (!*q)
Chris Allegretta's avatar
Chris Allegretta committed
143
	    return haystack;
Chris Allegretta's avatar
Chris Allegretta committed
144
	haystack++;
Chris Allegretta's avatar
Chris Allegretta committed
145
    }
146
    return NULL;
Chris Allegretta's avatar
Chris Allegretta committed
147
148
}

Chris Allegretta's avatar
Chris Allegretta committed
149
150
const char *strstrwrapper(const char *haystack, const char *needle,
	const char *rev_start, int line_pos)
Chris Allegretta's avatar
Chris Allegretta committed
151
{
152
#ifdef HAVE_REGEX_H
153
    if (ISSET(USE_REGEXP)) {
Chris Allegretta's avatar
Chris Allegretta committed
154
	if (!ISSET(REVERSE_SEARCH)) {
Chris Allegretta's avatar
Chris Allegretta committed
155
	    if (!regexec(&search_regexp, haystack, 10, regmatches, (line_pos > 0) ? REG_NOTBOL : 0))
Chris Allegretta's avatar
Chris Allegretta committed
156
		return haystack + regmatches[0].rm_so;
Chris Allegretta's avatar
Chris Allegretta committed
157
	}
158
#ifndef NANO_SMALL
Chris Allegretta's avatar
Chris Allegretta committed
159
160
	else {
	    const char *i, *j;
161

162
	    /* do a quick search forward first */
Chris Allegretta's avatar
Chris Allegretta committed
163
	    if (!regexec(&search_regexp, haystack, 10, regmatches, 0)) {
164
		/* there's a match somewhere in the line - now search for it backwards, much slower */
165
		for (i = rev_start; i >= haystack; --i) {
Chris Allegretta's avatar
Chris Allegretta committed
166
		    if (!regexec(&search_regexp, i, 10, regmatches, (i > haystack) ? REG_NOTBOL : 0)) {
Chris Allegretta's avatar
Chris Allegretta committed
167
168
169
170
			j = i + regmatches[0].rm_so;
			if (j <= rev_start)
			    return j;
		    }
171
		}
Chris Allegretta's avatar
Chris Allegretta committed
172
	    }
173
	}
Chris Allegretta's avatar
Chris Allegretta committed
174
#endif
175
176
	return 0;
    }
177
#endif
178
#ifndef NANO_SMALL
179
    if (ISSET(CASE_SENSITIVE)) {
180
	if (ISSET(REVERSE_SEARCH))
Chris Allegretta's avatar
Chris Allegretta committed
181
	    return revstrstr(haystack, needle, rev_start);
182
        else
183
	    return strstr(haystack, needle);
Chris Allegretta's avatar
Chris Allegretta committed
184
    } else {
185
	if (ISSET(REVERSE_SEARCH))
186
	    return revstristr(haystack, needle, rev_start);
187
188
	else
#endif
189
	    return stristr(haystack, needle);
190
#ifndef NANO_SMALL
Chris Allegretta's avatar
Chris Allegretta committed
191
    }
192
#endif
Chris Allegretta's avatar
Chris Allegretta committed
193
}
Chris Allegretta's avatar
Chris Allegretta committed
194

195
196
/* This is a wrapper for the perror function.  The wrapper takes care of 
 * ncurses, calls perror (which writes to STDERR), then refreshes the 
Chris Allegretta's avatar
Chris Allegretta committed
197
 * screen.  Note that nperror causes the window to flicker once. */
198
199
200
201
202
203
204
205
void nperror(const char *s) {
	/* leave ncurses mode, go to the terminal */
    if (endwin() != ERR) {
	perror(s);		/* print the error */
	total_refresh();	/* return to ncurses and repaint */
    }
}

Chris Allegretta's avatar
Chris Allegretta committed
206
207
/* Thanks BG, many ppl have been asking for this... */
void *nmalloc(size_t howmuch)
Chris Allegretta's avatar
Chris Allegretta committed
208
{
Chris Allegretta's avatar
Chris Allegretta committed
209
    void *r;
Chris Allegretta's avatar
Chris Allegretta committed
210

Chris Allegretta's avatar
Chris Allegretta committed
211
212
213
214
215
216
217
    /* Panic save? */

    if (!(r = malloc(howmuch)))
	die(_("nano: malloc: out of memory!"));

    return r;
}
Chris Allegretta's avatar
Chris Allegretta committed
218

219
/* We're going to need this too - Hopefully this will minimize
Chris Allegretta's avatar
Chris Allegretta committed
220
   the transition cost of moving to the appropriate function. */
221
char *charalloc(size_t howmuch)
222
{
Chris Allegretta's avatar
Chris Allegretta committed
223
    char *r;
224
225
226

    /* Panic save? */

Chris Allegretta's avatar
Chris Allegretta committed
227
    if (!(r = (char *)calloc(howmuch, sizeof (char))))
228
229
	die(_("nano: calloc: out of memory!"));

Chris Allegretta's avatar
Chris Allegretta committed
230
    return r;
231
232
}

Chris Allegretta's avatar
Chris Allegretta committed
233
void *nrealloc(void *ptr, size_t howmuch)
Chris Allegretta's avatar
Chris Allegretta committed
234
{
Chris Allegretta's avatar
Chris Allegretta committed
235
    void *r;
Chris Allegretta's avatar
Chris Allegretta committed
236

Chris Allegretta's avatar
Chris Allegretta committed
237
    if (!(r = realloc(ptr, howmuch)))
Jordi Mallach's avatar
   
Jordi Mallach committed
238
	die(_("nano: realloc: out of memory!"));
Chris Allegretta's avatar
Chris Allegretta committed
239
240
241

    return r;
}
Robert Siemborski's avatar
Robert Siemborski committed
242

Chris Allegretta's avatar
Chris Allegretta committed
243
244
245
/* Copy one malloc()ed string to another pointer.  Should be used as:
 * dest = mallocstrcpy(dest, src); */
char *mallocstrcpy(char *dest, const char *src)
246
{
247
    if (src == dest)
Chris Allegretta's avatar
Chris Allegretta committed
248
	return dest;
249

Chris Allegretta's avatar
Chris Allegretta committed
250
    if (dest)
251
252
	free(dest);

Chris Allegretta's avatar
Chris Allegretta committed
253
254
    if (!src)
	return NULL;
255

256
    dest = charalloc(strlen(src) + 1);
257
258
259
260
261
    strcpy(dest, src);

    return dest;
}

Chris Allegretta's avatar
Chris Allegretta committed
262
/* Append a new magic-line to filebot. */
263
264
void new_magicline(void)
{
Robert Siemborski's avatar
Robert Siemborski committed
265
    filebot->next = nmalloc(sizeof(filestruct));
266
    filebot->next->data = charalloc(1);
Robert Siemborski's avatar
Robert Siemborski committed
267
268
269
270
271
272
    filebot->next->data[0] = '\0';
    filebot->next->prev = filebot;
    filebot->next->next = NULL;
    filebot->next->lineno = filebot->lineno + 1;
    filebot = filebot->next;
    totlines++;
273
    totsize++;
Robert Siemborski's avatar
Robert Siemborski committed
274
}
Chris Allegretta's avatar
Chris Allegretta committed
275

276
#ifndef DISABLE_TABCOMP
Chris Allegretta's avatar
Chris Allegretta committed
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/*
 * Routine to see if a text string is matched by a wildcard pattern.
 * Returns TRUE if the text is matched, or FALSE if it is not matched
 * or if the pattern is invalid.
 *  *		matches zero or more characters
 *  ?		matches a single character
 *  [abc]	matches 'a', 'b' or 'c'
 *  \c		quotes character c
 * Adapted from code written by Ingo Wilken, and
 * then taken from sash, Copyright (c) 1999 by David I. Bell
 * Permission is granted to use, distribute, or modify this source,
 * provided that this copyright notice remains intact.
 * Permission to distribute this code under the GPL has been granted.
 */
int check_wildcard_match(const char *text, const char *pattern)
{
Chris Allegretta's avatar
Chris Allegretta committed
293
294
    const char *retrypat;
    const char *retrytext;
Chris Allegretta's avatar
Chris Allegretta committed
295
296
297
298
    int ch;
    int found;
    int len;

Chris Allegretta's avatar
Chris Allegretta committed
299
300
    retrypat = NULL;
    retrytext = NULL;
Chris Allegretta's avatar
Chris Allegretta committed
301
302
303
304
305
306

    while (*text || *pattern) {
	ch = *pattern++;

	switch (ch) {
	case '*':
Chris Allegretta's avatar
Chris Allegretta committed
307
308
	    retrypat = pattern;
	    retrytext = text;
Chris Allegretta's avatar
Chris Allegretta committed
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
	    break;

	case '[':
	    found = FALSE;

	    while ((ch = *pattern++) != ']') {
		if (ch == '\\')
		    ch = *pattern++;

		if (ch == '\0')
		    return FALSE;

		if (*text == ch)
		    found = TRUE;
	    }
	    len = strlen(text);
	    if (found == FALSE && len != 0) {
		return FALSE;
	    }
	    if (found == TRUE) {
		if (strlen(pattern) == 0 && len == 1) {
		    return TRUE;
		}
		if (len != 0) {
		    text++;
		    continue;
		}
	    }

	    /* fall into next case */

	case '?':
	    if (*text++ == '\0')
		return FALSE;

	    break;

	case '\\':
	    ch = *pattern++;

	    if (ch == '\0')
		return FALSE;

	    /* fall into next case */

	default:
	    if (*text == ch) {
		if (*text)
		    text++;
		break;
	    }

	    if (*text) {
Chris Allegretta's avatar
Chris Allegretta committed
362
363
		pattern = retrypat;
		text = ++retrytext;
Chris Allegretta's avatar
Chris Allegretta committed
364
365
366
367
368
369
		break;
	    }

	    return FALSE;
	}

Chris Allegretta's avatar
Chris Allegretta committed
370
	if (!pattern)
Chris Allegretta's avatar
Chris Allegretta committed
371
372
373
374
375
	    return FALSE;
    }

    return TRUE;
}
376
#endif