utils.c 8.41 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>
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
27
#include "config.h"
Chris Allegretta's avatar
Chris Allegretta committed
28
#include "proto.h"
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
29
#include "nano.h"
Chris Allegretta's avatar
Chris Allegretta committed
30

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

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
int num_of_digits(int n)
{
    int i = 1;

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

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

    return i;
}

David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/* 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, int true_len)
{
    int i;
    if (strlen(str) < true_len) {
	for (i = 0; i < true_len; i++) {
	    if (str[i] == '\0')
		str[i] = '\n';
	}
    }
}

/* 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)
{
    int i, true_len = strlen(str);
    if (strchr(str, '\n')) {
	for (i = 0; i < true_len; i++) {
	    if (str[i] == '\n')
		str[i] = '\0';
	}
    }
}

Chris Allegretta's avatar
Chris Allegretta committed
79
80
81
82
83
84
85
86
87
88
89
/* Lower case a string - must be null terminated */
void lowercase(char *src)
{
    long i = 0;

    while (src[i] != 0) {
	src[i] = (char) tolower(src[i]);
	i++;
    }
}

90
91
/* None of this is needed if we're using NANO_SMALL! */
#ifndef NANO_SMALL
Chris Allegretta's avatar
Chris Allegretta committed
92
93
94
95
96
97
98
99
100
101
102
103
104
char *revstrstr(char *haystack, char *needle, char *rev_start)
{
    char *p, *q, *r;

    for(p = rev_start ; p >= haystack ; --p) {
	for (r = p, q = needle ; (*q == *r) && (*q != '\0') ; r++, q++)
	    ;
	if (*q == '\0')
	    return p;
    }
    return 0;
}

105
char *revstristr(char *haystack, char *needle, char *rev_start)
Chris Allegretta's avatar
Chris Allegretta committed
106
107
108
109
110
111
112
113
114
115
116
{
    char *p, *q, *r;

    for(p = rev_start ; p >= haystack ; --p) {
	for (r = p, q = needle ; (tolower(*q) == tolower(*r)) && (*q != '\0') ; r++, q++)
	    ;
	if (*q == '\0')
	    return p;
    }
    return 0;
}
Chris Allegretta's avatar
Chris Allegretta committed
117
#endif /* NANO_SMALL */
Chris Allegretta's avatar
Chris Allegretta committed
118

119
/* This is now mutt's version (called mutt_stristr) because it doesn't
Chris Allegretta's avatar
typo    
Chris Allegretta committed
120
   use memory allocation to do a simple search (yuck). */
121
char *stristr(char *haystack, char *needle)
Chris Allegretta's avatar
Chris Allegretta committed
122
{
123
    const char *p, *q;
Chris Allegretta's avatar
Chris Allegretta committed
124

125
    if (!haystack)
Chris Allegretta's avatar
Chris Allegretta committed
126
	return NULL;
127
128
129
    if (!needle)  
	return (haystack);
    
Chris Allegretta's avatar
Chris Allegretta committed
130
    while (*(p = haystack)) {
131
132
133
134
	for (q = needle; *p && *q && tolower (*p) == tolower (*q); p++, q++)
	    ;
	if (!*q)
	    return (haystack);
Chris Allegretta's avatar
Chris Allegretta committed
135
	haystack++;
Chris Allegretta's avatar
Chris Allegretta committed
136
    }
137
    return NULL;
Chris Allegretta's avatar
Chris Allegretta committed
138
139
}

Chris Allegretta's avatar
Chris Allegretta committed
140
char *strstrwrapper(char *haystack, char *needle, char *rev_start)
Chris Allegretta's avatar
Chris Allegretta committed
141
{
Chris Allegretta's avatar
Chris Allegretta committed
142

143
#ifdef HAVE_REGEX_H
Chris Allegretta's avatar
Chris Allegretta committed
144
145
    int  result;

146
    if (ISSET(USE_REGEXP)) {
Chris Allegretta's avatar
Chris Allegretta committed
147
148
149
150
	if (!ISSET(REVERSE_SEARCH)) {
	    result = regexec(&search_regexp, haystack, 10, regmatches, 0);
	    if (!result)
		return haystack + regmatches[0].rm_so;
151
#ifndef NANO_SMALL
Chris Allegretta's avatar
Chris Allegretta committed
152
	} else {
153
154
	    char *i, *j;

155
	    /* do a quick search forward first */
Chris Allegretta's avatar
Chris Allegretta committed
156
	    if (!(regexec(&search_regexp, haystack, 10, regmatches, 0))) {
157
		/* there's a match somewhere in the line - now search for it backwards, much slower */
Chris Allegretta's avatar
Chris Allegretta committed
158
159
160
161
162
163
164
		for(i = rev_start ; i >= haystack ; --i)
		    if (!(result = regexec(&search_regexp, i, 10, regmatches, 0))) {
			j = i + regmatches[0].rm_so;
			if (j <= rev_start)
			    return j;
		    }
	    }
165
#endif
166
	}
167
168
	return 0;
    }
169
#endif
170
#ifndef NANO_SMALL
171
    if (ISSET(CASE_SENSITIVE)) {
172
	if (ISSET(REVERSE_SEARCH))
Chris Allegretta's avatar
Chris Allegretta committed
173
	    return revstrstr(haystack, needle, rev_start);
174
175
176
        else
	    return strstr(haystack,needle);

Chris Allegretta's avatar
Chris Allegretta committed
177
    } else {
178
	if (ISSET(REVERSE_SEARCH))
179
	    return revstristr(haystack, needle, rev_start);
180
181
	else
#endif
182
	    return stristr(haystack, needle);
183
#ifndef NANO_SMALL
Chris Allegretta's avatar
Chris Allegretta committed
184
    }
185
#endif
Chris Allegretta's avatar
Chris Allegretta committed
186
}
Chris Allegretta's avatar
Chris Allegretta committed
187

188
189
190
191
192
193
194
195
196
197
198
199
/* This is a wrapper for the perror function.  The wrapper takes care of 
 * ncurses, calls perror (which writes to STDERR), then refreshes the 
 * screen.  Note that nperror causes the window to flicker once.
 */
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
200
201
/* Thanks BG, many ppl have been asking for this... */
void *nmalloc(size_t howmuch)
Chris Allegretta's avatar
Chris Allegretta committed
202
{
Chris Allegretta's avatar
Chris Allegretta committed
203
    void *r;
Chris Allegretta's avatar
Chris Allegretta committed
204

Chris Allegretta's avatar
Chris Allegretta committed
205
206
207
208
209
210
211
    /* Panic save? */

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

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

213
214
215
/* We're going to need this too - Hopefully this will minimize
   the transition cost of moving to the apropriate function. */
char *charalloc(size_t howmuch)
216
217
218
219
220
{
    void *r;

    /* Panic save? */

221
    if (!(r = calloc(howmuch, sizeof (char))))
222
223
	die(_("nano: calloc: out of memory!"));

224
    return (char *) r;
225
226
}

Chris Allegretta's avatar
Chris Allegretta committed
227
void *nrealloc(void *ptr, size_t howmuch)
Chris Allegretta's avatar
Chris Allegretta committed
228
{
Chris Allegretta's avatar
Chris Allegretta committed
229
    void *r;
Chris Allegretta's avatar
Chris Allegretta committed
230

Chris Allegretta's avatar
Chris Allegretta committed
231
    if (!(r = realloc(ptr, howmuch)))
Jordi Mallach's avatar
   
Jordi Mallach committed
232
	die(_("nano: realloc: out of memory!"));
Chris Allegretta's avatar
Chris Allegretta committed
233
234
235

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

237
/* Copy one malloc()ed string to another pointer.
238
239
240

   Should be used as dest = mallocstrcpy(dest, src);
*/
241
void *mallocstrcpy(char *dest, char *src)
242
243
{

244
245
246
247

    if (src == dest)
	return src;

248
249
250
    if (dest != NULL)
	free(dest);

251
252
253
254
255
    if (src == NULL) {
	dest = NULL;
	return(dest);
    }

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

    return dest;
}


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

277
#ifndef DISABLE_TABCOMP
Chris Allegretta's avatar
Chris Allegretta committed
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
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
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
/*
 * 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)
{
    const char *retryPat;
    const char *retryText;
    int ch;
    int found;
    int len;

    retryPat = NULL;
    retryText = NULL;

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

	switch (ch) {
	case '*':
	    retryPat = pattern;
	    retryText = text;
	    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) {
		pattern = retryPat;
		text = ++retryText;
		break;
	    }

	    return FALSE;
	}

	if (pattern == NULL)
	    return FALSE;
    }

    return TRUE;
}
377
#endif