Files
pcas/src/libCom/misc/epicsString.c
2016-12-07 16:36:58 -06:00

372 lines
9.2 KiB
C

/*************************************************************************\
* Copyright (c) 2009 Helmholtz-Zentrum Berlin fuer Materialien und Energie.
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Authors: Jun-ichi Odagiri, Marty Kraimer, Eric Norum,
* Mark Rivers, Andrew Johnson, Ralph Lange
*
* Routines in this file should have corresponding test code in
* libCom/test/epicsStringTest.c
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <ctype.h>
#define epicsExportSharedSymbols
#include "epicsStdio.h"
#include "cantProceed.h"
#include "epicsString.h"
/* Deprecated, use epicsStrnRawFromEscaped() instead */
int dbTranslateEscape(char *dst, const char *src)
{
size_t big_enough = strlen(src) + 1;
return epicsStrnRawFromEscaped(dst, big_enough, src, big_enough);
}
int epicsStrnRawFromEscaped(char *dst, size_t dstlen, const char *src,
size_t srclen)
{
int rem = dstlen;
int ndst = 0;
while (srclen--) {
int c = *src++;
#define OUT(chr) if (--rem > 0) ndst++, *dst++ = chr
if (!c) break;
input:
if (c != '\\') {
OUT(c);
continue;
}
if (!srclen-- || !(c = *src++)) break;
switch (c) {
case 'a': OUT('\a'); break;
case 'b': OUT('\b'); break;
case 'f': OUT('\f'); break;
case 'n': OUT('\n'); break;
case 'r': OUT('\r'); break;
case 't': OUT('\t'); break;
case 'v': OUT('\v'); break;
case '\\': OUT('\\'); break;
case '\'': OUT('\''); break;
case '\"': OUT('\"'); break;
case '0' :case '1' :case '2' :case '3' :
case '4' :case '5' :case '6' :case '7' :
{ /* \ooo */
unsigned int u = c - '0';
if (!srclen-- || !(c = *src++)) {
OUT(u); goto done;
}
if (c < '0' || c > '7') {
OUT(u); goto input;
}
u = u << 3 | (c - '0');
if (!srclen-- || !(c = *src++)) {
OUT(u); goto done;
}
if (c < '0' || c > '7') {
OUT(u); goto input;
}
u = u << 3 | (c - '0');
if (u > 0377) {
/* Undefined behaviour! */
}
OUT(u);
}
break;
case 'x' :
{ /* \xXXX... */
unsigned int u = 0;
if (!srclen-- || !(c = *src++ & 0xff))
goto done;
while (isxdigit(c)) {
u = u << 4 | ((c > '9') ? toupper(c) - 'A' + 10 : c - '0');
if (u > 0xff) {
/* Undefined behaviour! */
}
if (!srclen-- || !(c = *src++ & 0xff)) {
OUT(u);
goto done;
}
}
OUT(u);
goto input;
}
default:
OUT(c);
}
#undef OUT
}
done:
if (dstlen)
*dst = '\0';
return ndst;
}
int epicsStrnEscapedFromRaw(char *dst, size_t dstlen, const char *src,
size_t srclen)
{
int rem = dstlen;
int ndst = 0;
if (dst == src)
return -1;
while (srclen--) {
int c = *src++;
#define OUT(chr) ndst++; if (--rem > 0) *dst++ = chr
switch (c) {
case '\a': OUT('\\'); OUT('a'); break;
case '\b': OUT('\\'); OUT('b'); break;
case '\f': OUT('\\'); OUT('f'); break;
case '\n': OUT('\\'); OUT('n'); break;
case '\r': OUT('\\'); OUT('r'); break;
case '\t': OUT('\\'); OUT('t'); break;
case '\v': OUT('\\'); OUT('v'); break;
case '\\': OUT('\\'); OUT('\\'); break;
case '\'': OUT('\\'); OUT('\''); break;
case '\"': OUT('\\'); OUT('\"'); break;
default:
if (isprint(c & 0xff)) {
OUT(c);
break;
}
OUT('\\');
OUT('0' + ((c & 0300) >> 6));
OUT('0' + ((c & 0070) >> 3));
OUT('0' + (c & 0007));
}
#undef OUT
}
if (dstlen)
*dst = '\0';
return ndst;
}
size_t epicsStrnEscapedFromRawSize(const char *src, size_t srclen)
{
size_t ndst = srclen;
while (srclen--) {
int c = *src++;
switch (c) {
case '\a': case '\b': case '\f': case '\n':
case '\r': case '\t': case '\v': case '\\':
case '\'': case '\"':
ndst++;
break;
default:
if (!isprint(c & 0xff))
ndst += 3;
}
}
return ndst;
}
int epicsStrCaseCmp(const char *s1, const char *s2)
{
while (1) {
int ch1 = toupper((int) *s1);
int ch2 = toupper((int) *s2);
if (ch2 == 0) return (ch1 != 0);
if (ch1 == 0) return -1;
if (ch1 < ch2) return -1;
if (ch1 > ch2) return 1;
s1++;
s2++;
}
}
int epicsStrnCaseCmp(const char *s1, const char *s2, size_t len)
{
size_t i = 0;
while (i++ < len) {
int ch1 = toupper((int) *s1);
int ch2 = toupper((int) *s2);
if (ch2 == 0) return (ch1 != 0);
if (ch1 == 0) return -1;
if (ch1 < ch2) return -1;
if (ch1 > ch2) return 1;
s1++;
s2++;
}
return 0;
}
char * epicsStrDup(const char *s)
{
return strcpy(mallocMustSucceed(strlen(s)+1, "epicsStrDup"), s);
}
int epicsStrPrintEscaped(FILE *fp, const char *s, size_t len)
{
int nout = 0;
while (len--) {
char c = *s++;
switch (c) {
case '\a': nout += fprintf(fp, "\\a"); break;
case '\b': nout += fprintf(fp, "\\b"); break;
case '\f': nout += fprintf(fp, "\\f"); break;
case '\n': nout += fprintf(fp, "\\n"); break;
case '\r': nout += fprintf(fp, "\\r"); break;
case '\t': nout += fprintf(fp, "\\t"); break;
case '\v': nout += fprintf(fp, "\\v"); break;
case '\\': nout += fprintf(fp, "\\\\"); break;
case '\'': nout += fprintf(fp, "\\'"); break;
case '\"': nout += fprintf(fp, "\\\""); break;
default:
if (isprint(0xff & (int)c))
nout += fprintf(fp, "%c", c);
else
nout += fprintf(fp, "\\%03o", (unsigned char)c);
break;
}
}
return nout;
}
/* Until Base requires POSIX 2008 we must provide our own implementation */
size_t epicsStrnLen(const char *s, size_t maxlen)
{
size_t i;
for (i=0; i<maxlen; i++) {
if(s[i]=='\0')
return i;
}
return i;
}
int epicsStrGlobMatch(const char *str, const char *pattern)
{
const char *cp = NULL, *mp = NULL;
while ((*str) && (*pattern != '*')) {
if ((*pattern != *str) && (*pattern != '?'))
return 0;
pattern++;
str++;
}
while (*str) {
if (*pattern == '*') {
if (!*++pattern)
return 1;
mp = pattern;
cp = str+1;
}
else if ((*pattern == *str) || (*pattern == '?')) {
pattern++;
str++;
}
else {
pattern = mp;
str = cp++;
}
}
while (*pattern == '*')
pattern++;
return !*pattern;
}
char * epicsStrtok_r(char *s, const char *delim, char **lasts)
{
const char *spanp;
int c, sc;
char *tok;
if (s == NULL && (s = *lasts) == NULL)
return NULL;
/*
* Skip (span) leading delimiters (s += strspn(s, delim), sort of).
*/
cont:
c = *s++;
for (spanp = delim; (sc = *spanp++) != 0;) {
if (c == sc)
goto cont;
}
if (c == 0) { /* no non-delimiter characters */
*lasts = NULL;
return NULL;
}
tok = s - 1;
/*
* Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
* Note that delim must have one NUL; we stop if we see that, too.
*/
for (;;) {
c = *s++;
spanp = delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
*lasts = s;
return tok;
}
} while (sc != 0);
}
}
unsigned int epicsStrHash(const char *str, unsigned int seed)
{
unsigned int hash = seed;
char c;
while ((c = *str++)) {
hash ^= ~((hash << 11) ^ c ^ (hash >> 5));
if (!(c = *str++)) break;
hash ^= (hash << 7) ^ c ^ (hash >> 3);
}
return hash;
}
unsigned int epicsMemHash(const char *str, size_t length, unsigned int seed)
{
unsigned int hash = seed;
while (length--) {
hash ^= ~((hash << 11) ^ *str++ ^ (hash >> 5));
if (!length--) break;
hash ^= (hash << 7) ^ *str++ ^ (hash >> 3);
}
return hash;
}