/* * Gophernicus * * Copyright (c) 2009-2018 Kim Holviala * Copyright (c) 2019 Gophernicus Developers * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "gophernicus.h" /* * Repeat a character num times and zero-terminate */ void strrepeat(char *dest, char c, size_t num) { memset(dest, c, num); dest[num] = '\0'; } /* * Replace characters in-place */ void strreplace(char *str, char from, char to) { while (*str) { if (*str == from) *str = to; str++; } } /* * Cut string to width, return resulting width (UTF-8 aware) */ size_t strcut(char *str, size_t width) { unsigned char c = '\0'; int w = 0; int i; while (width-- && (c = *str++)) { if (c >= 0x80 && (*str & 0xc0) == 0x80) { i = 0; if ((c & 0xf8) == 0xf0) i = 3; else if ((c & 0xf0) == 0xe0) i = 2; else if ((c & 0xe0) == 0xc0) i = 1; while (i--) if (!*str++) break; } w++; } if (c) *str = '\0'; return w; } /* * Match key and return value (key: value) */ char *strkey(char *header, char *key) { char *c; size_t len; if ((len = strlen(key)) == 0) return NULL; if (strncasecmp(header, key, len) == MATCH) { c = header + len; do { c++; } while (*c == ' ' || *c == '\t'); if (*c != ':') return NULL; do { c++; } while (*c == ' ' || *c == '\t'); return c; } return NULL; } /* * Return last character of a string */ char strlast(char *str) { int len; if ((len = (int)strlen(str) - 1) >= 0) return str[len]; else return 0; } /* * Remove CRLF from a string */ void chomp(char *str) { char *c; if ((c = strrchr(str, '\n'))) *c = '\0'; if ((c = strrchr(str, '\r'))) *c = '\0'; } /* * Return charset name */ char *strcharset(int charset) { if (charset == AUTO) return "auto"; if (charset == US_ASCII) return "US-ASCII"; if (charset == ISO_8859_1) return "ISO-8859-1"; if (charset == UTF_8) return "UTF-8"; return "(unknown)"; } /* * Convert a string between UTF-8, ISO-8859-1 and US-ASCII */ void strniconv(int charset, char *out, char *in, size_t outsize) { char ascii[] = ASCII; unsigned long c; size_t len; int i; /* Loop through the input string */ len = strlen(in); while (--outsize && len > 0) { /* Get one input char */ c = (unsigned char) *in++; len--; /* 7-bit chars are the same in all three charsets */ if (c < 0x80) { *out++ = (unsigned char) c; continue; } /* Assume ISO-8859-1 which requires 0 extra bytes */ i = 0; /* UTF-8? (We'll actually check the next char here, not current) */ if ((*in & 0xc0) == 0x80) { /* Four-byte UTF-8? */ if ((c & 0xf8) == 0xf0 && len >= 3) { c &= 0x07; i = 3; } /* Three-byte UTF-8? */ else if ((c & 0xf0) == 0xe0 && len >= 2) { c &= 0x0f; i = 2; } /* Two-byte UTF-8? */ else if ((c & 0xe0) == 0xc0 && len >= 1) { c &= 0x1f; i = 1; } /* Parse rest of the UTF-8 bytes */ while (i--) { c <<= 6; c |= *in++ & 0x3f; len--; } } /* * At this point we've got one 32bit UTF character in c and * we're ready to convert it to the specified output charset */ /* Handle UTF-8 */ if (charset == UTF_8) { i = 0; /* Two-byte encoding? */ if (c < 0x800 && outsize > 2) { *out++ = (c >> 6) | 0xc0; i = 1; } /* Three-byte encoding? */ else if (c < 0x10000 && outsize > 3) { *out++ = (c >> 12) | 0xe0; i = 2; } /* Four-byte encoding? */ else if (c < 0x110000 && outsize > 4) { *out++ = (c >> 18) | 0xf0; i = 3; } /* Encode rest of the UTF-8 bytes */ while (i--) { *out++ = ((c >> (i * 6)) & 0x3f) | 0x80; outsize--; } continue; } /* Handle ISO-8859-1 */ if (charset == ISO_8859_1) { if (c >= 0xa0 && c <= 0xff) *out++ = (unsigned char) c; else *out++ = UNKNOWN; continue; } /* Handle all other charsets as 7-bit US-ASCII */ if (c >= 0x80 && c <= 0xff) *out++ = ascii[c - 0x80]; else *out++ = UNKNOWN; } /* Zero-terminate output */ *out = '\0'; } /* * Encode string with #OCT encoding */ void strnencode(char *out, const char *in, size_t outsize) { unsigned char c; /* Loop through the input string */ while (--outsize) { /* End of source? */ if (!(c = *in++)) break; /* Need to encode the char? */ if (c < '+' || c > '~') { /* Can we fit the encoded version into outbuffer? */ if (outsize < 5) break; /* Output encoded char */ snprintf(out, outsize, "#%.3o", c); out += 4; } /* Copy regular chars */ else *out++ = c; } /* Zero-terminate output */ *out = '\0'; } /* * Decode both %HEX and #OCT encodings */ void strndecode(char *out, char *in, size_t outsize) { unsigned char c; unsigned int i; /* Loop through the input string */ while (--outsize) { /* End of source? */ if (!(c = *in++)) break; /* Parse %hex encoding */ if (c == '%' && strlen(in) >= 2) { sscanf(in, "%2x", &i); *out++ = i; in += 2; continue; } /* Parse #octal encoding */ if (c == '#' && strlen(in) >= 3) { sscanf(in, "%3o", &i); *out++ = i; in += 3; continue; } /* Copy non-encoded chars */ *out++ = c; } /* Zero-terminate output */ *out = '\0'; } /* * Format number to human-readable filesize with unit */ void strfsize(char *out, off_t size, size_t outsize) { static char *unit[] = { UNITS }; int u; float s; /* Start with kilobytes */ s = ((float) size) / 1024; u = 0; /* Loop through the units until the size is small enough */ while (s >= 1000 && unit[(u + 1)]) { s = s / 1024; u++; } /* Format size */ snprintf(out, outsize, "%7.1f %s", s, unit[u]); } #ifndef HAVE_STRLCPY /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0) { while (--n != 0) { if ((*d++ = *s++) == '\0') break; } } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ size_t strlcat(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } #endif