blob: 7e93327bdc589853621ed5402bfbe87aedceeb15 [file] [edit]
/* **********************************************************
* Copyright (c) 2011-2024 Google, Inc. All rights reserved.
* Copyright (c) 2007-2010 VMware, Inc. All rights reserved.
* **********************************************************/
/* Dr. Memory: the memory debugger
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License, and no later version.
* This library 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
* Library General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Code shared between Dr. Memory and the DRMF Extensions (which don't
* want to link the full utils.c)
*/
#include "dr_api.h"
#include "utils.h"
#include <ctype.h> /* for tolower */
#include <string.h>
char *
strnchr(const char *str, int find, size_t max)
{
register const char *s = str;
register char c = (char) find;
while (true) {
if (s - str >= max)
return NULL;
if (*s == c)
return (char *) s;
if (*s == '\0')
return NULL;
s++;
}
return NULL;
}
/* Not available in ntdll CRT so we supply our own.
* It is available on Mac and Android, and we want to avoid it for libs that do not
* want a libc dependence.
*/
#if !defined(MACOS) && !defined(ANDROID) && !defined(NOLINK_STRCASESTR)
char *
strcasestr(const char *text, const char *pattern)
{
const char *cur_text, *cur_pattern, *root;
cur_text = text;
root = text;
cur_pattern = pattern;
while (true) {
if (*cur_pattern == '\0')
return (char *) root;
if (*cur_text == '\0')
return NULL;
/* XXX DRi#943: toupper is better, for int18n, and we need to call
* islower() first to be safe for all tolower() implementations.
* Even better would be switching to our own locale-independent case
* folding.
*/
if ((char)tolower(*cur_text) == (char)tolower(*cur_pattern)) {
cur_text++;
cur_pattern++;
} else {
root++;
cur_text = root;
cur_pattern = pattern;
}
}
}
#endif
char *
drmem_strdup(const char *src, heapstat_t type)
{
char *dup = NULL;
if (src != NULL) {
size_t len = strlen(src);
dup = global_alloc(len+1, type);
strncpy(dup, src, len+1);
}
return dup;
}
char *
drmem_strndup(const char *src, size_t max, heapstat_t type)
{
char *dup = NULL;
/* deliberately not calling strlen on src since may be quite long */
const char *c;
size_t sz;
for (c = src; *c != '\0' && (c - src < max); c++)
; /* nothing */
sz = (c - src < max) ? c -src : max;
if (src != NULL) {
dup = global_alloc(sz + 1, type);
strncpy(dup, src, sz);
dup[sz] = '\0';
}
return dup;
}
/* see description in header */
const char *
find_next_line(const char *start, const char *eof, const char **sol,
const char **eol DR_PARAM_OUT, bool skip_ws)
{
const char *line = start, *newline, *next_line;
/* First, set "line" to start of line and "newline" to end (pre-whitespace) */
/* We have to use strnchr to avoid SIGBUS on non-Windows */
newline = strnchr(line, '\n', eof - line);
if (newline == NULL) {
newline = eof; /* handle EOF w/o trailing \n */
next_line = newline + 1;
} else {
for (next_line = newline; *next_line == '\r' || *next_line == '\n';
next_line++)
; /* nothing */
if (*(newline-1) == '\r') /* always skip CR */
newline--;
if (skip_ws) {
for (; newline > line && (*(newline-1) == ' ' || *(newline-1) == '\t');
newline--)
; /* nothing */
}
}
if (skip_ws) {
for (; line < newline && (*line == ' ' || *line == '\t'); line++)
; /* nothing */
}
if (sol != NULL)
*sol = line;
if (eol != NULL)
*eol = newline;
return next_line;
}