StringUtils.c

/*
**  Apple Macintosh Developer Technical Support
**
**  Collection of String Utilities for DTS Sample code
**
**  File:       StringUtils.c
**
**  Copyright © 1988-1993 Apple Computer, Inc.
**  All rights reserved.
*/
 
/* You may incorporate this sample code into your applications without
** restriction, though the sample code has been provided "AS IS" and the
** responsibility for its operation is 100% yours.  However, what you are
** not permitted to do is to redistribute the source as "DSC Sample Code"
** after having made changes. If you're going to re-distribute the source,
** we require that you make it clear in the source that the code was
** descended from Apple Sample Code, but that you've made changes. */
 
#ifndef __MEMORY__
#include <Memory.h>
#endif
 
#ifndef __STRINGUTILS__
#include "StringUtils.h"
#endif
 
 
/* These functions should be linked into whatever segment holds main().  This will
** guarantee that the functions will always be in memory when called.  It is important
** that they are in memory, because if a pointer is passed in that points into an
** unlocked handle, the mere fact that the code needs to get loaded may cause the
** handle that is pointed into to move.  If you stick to these string functions,
** you will not have to worry about the handle moving when the string function is
** called.  If you have your own string functions, and you wish the same safety
** factor, link the string handling code into the same segment as main(), as you
** do with these string functions. */
 
static short    gBase;
static Boolean  gHandleChars;
 
 
 
/*****************************************************************************/
/*****************************************************************************/
 
 
 
/* Return the length of the c-string.  (Same as strlen, but this function isn't
** part of the string library.  The entire library may be more than you wish to
** link into the code segment that holds main, so this (and other) standard
** library function has been duplicated here. */
 
short   clen(char *cptr)
{
    short   i;
 
    for (i = 0; cptr[i]; ++i) {};
    return(i);
}
 
 
 
/*****************************************************************************/
 
 
 
/* Catenate two c-strings. */
 
char    *ccat(char *s1, char *s2)
{
    ccpy(s1 + clen(s1), s2);
    return(s1);
}
 
 
 
/*****************************************************************************/
 
 
 
/* Copy a c-string. */
 
char    *ccpy(char *s1, char *s2)
{
    char    *c1, *c2;
 
    c1 = s1;
    c2 = s2;
    while ((*c1++ = *c2++) != 0) {};
    return(s1);
}
 
 
 
/*****************************************************************************/
 
 
 
/* Compare two pascal-strings. */
 
short   pcmp(StringPtr s1, StringPtr s2)
{
    short   i, len, j;
 
    if ((len = s1[0]) > s2[0]) len = s2[0];
 
    for (i = 1; i <= len; ++i) {
        j = ((unsigned short)s1[i] - (unsigned short)s2[i]);
        if (j) return(j);
    }
 
    return(s1[0] - s2[0]);
}
 
 
 
/*****************************************************************************/
 
 
 
/* Catenate two pascal-strings. */
 
void    pcat(StringPtr d, StringPtr s)
{
    short   i, j;
 
    if (((j = s[0]) + d[0]) > 255)
        j = 255 - d[0];
            /* Limit dest string to 255. */
 
    for (i = 0; i < j;) d[++d[0]] = s[++i];
}
 
 
 
/*****************************************************************************/
 
 
 
/* Copy a pascal-string. */
 
void    pcpy(StringPtr d, StringPtr s)
{
    short   i;
 
    i = *s;
    do {
        d[i] = s[i];
    } while (i--);
}
 
 
 
/*****************************************************************************/
 
 
 
/* Convert a c-string to a pascal-string. */
 
void    c2p(char *cptr)
{
    short   len;
 
    BlockMove(cptr, cptr + 1, len = clen(cptr));
    *cptr = len;
}
 
 
 
/*****************************************************************************/
 
 
 
/* Convert a pascal-string to a c-string. */
 
void    p2c(StringPtr cptr)
{
    unsigned char   len;
 
    BlockMove(cptr + 1, cptr, len = *cptr);
    cptr[len] = 0;
}
 
 
 
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
 
 
 
/* Catenate a single character multiple times onto the designated string. */
 
void    ccatchr(char *cptr, char c, short count)
{
    ccpychr(cptr + clen(cptr), c, count);
}
 
 
 
/*****************************************************************************/
 
 
 
/* Convert the value into text for the base-10 number and catenate it to
** the designated string.  The value is assumed to be signed.  If you wish
** to have an unsigned decimal value, call ccatnum with a base of 10. */
 
void    ccatpaddec(char *cptr, char padChr, short minApnd, short maxApnd, long v)
{
    ccatpadnum(cptr + clen(cptr), padChr, minApnd, maxApnd, v, -10);
        /* Catenate value base 10, signed. */
}
 
void    ccatdec(char *cptr, long v)
{
    ccatnum(cptr, v, -10);
}
 
 
 
/*****************************************************************************/
 
 
 
/* Convert the value into text for base-16, format it, and catenate it to the
** designated string.  ccatnum could be used, since it handles multiple bases,
** but ccathex allows for additional common formatting and padding of the
** hex value. */
 
void    ccatpadhex(char *cptr, char padChr, short minApnd, short maxApnd, long v)
{
    char    str[33], *sptr;
    short   len;
 
    cptr += clen(cptr);         /* We're appending, so point to the end of the string. */
    ccpynum(str, v, 16);        /* Generate minimum-digit hex value. */
 
    if ((len = clen(sptr = str)) > maxApnd)
        sptr = str + len - maxApnd;
 
    if ((len = clen(sptr)) < minApnd)
        if (padChr)
            ccatchr(cptr, padChr, (minApnd - len));
                /* if we have a pad character, and if necessary, pad the string. */
 
    ccat(cptr, sptr);           /* Add the hex digits to the string. */
}
 
void    ccathex(char *cptr, long v)
{
    ccatpadhex(cptr, 0, 0, 8, v);
}
 
 
 
/*****************************************************************************/
 
 
 
/* Convert the value into text for the designated base.  Catenate the text to
** the designated string. */
 
void    ccatpadnum(char *cptr, char padChr, short minApnd, short maxApnd, long v, short base)
{
    ccpypadnum(cptr + clen(cptr), padChr, minApnd, maxApnd, v, base);
}
 
void    ccatnum(char *cptr, long v, short base)
{
    ccpynum(cptr + clen(cptr), v, base);
}
 
 
 
/*****************************************************************************/
 
 
 
void    ccpychr(char *cptr, char c, short count)
{
    for (;count--; ++cptr) *cptr = c;
    *cptr = 0;
}
 
 
 
/*****************************************************************************/
 
 
 
void    ccpypaddec(char *cptr, char padChr, short minApnd, short maxApnd, long v)
{
    ccpypadnum(cptr, padChr, minApnd, maxApnd, v, -10);
}
 
void    ccpydec(char *cptr, long v)
{
    ccpynum(cptr, v, -10);
}
 
 
 
/*****************************************************************************/
 
 
 
void    ccpypadhex(char *cptr, char padChr, short minApnd, short maxApnd, long v)
{
    cptr[0] = 0;
    ccatpadhex(cptr, padChr, minApnd, maxApnd, v);
}
 
void    ccpyhex(char *cptr, long v)
{
    cptr[0] = 0;
    ccathex(cptr, v);
}
 
 
 
/*****************************************************************************/
 
 
 
void    ccpypadnum(char *cptr, char padChr, short minApnd, short maxApnd, long v, short base)
{
    pcpypadnum((StringPtr)cptr, padChr, minApnd, maxApnd, v, base);
    p2c((StringPtr)cptr);
}
 
void    ccpynum(char *cptr, long v, short base)
{
    pcpynum((StringPtr)cptr, v, base);
    p2c((StringPtr)cptr);
}
 
 
 
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
 
 
 
long    c2dec(char *cptr, short *charsUsed)
{
    return(c2num(cptr, 10, charsUsed));
}
 
 
 
/*****************************************************************************/
 
 
 
long    c2hex(char *cptr, short *charsUsed)
{
    return(c2num(cptr, 16, charsUsed));
}
 
 
 
/*****************************************************************************/
 
 
 
long    c2num(char *cptr, short base, short *charsUsed)
{
    Boolean firstDigit;
    short   i, sgn;
    short   c;
    long    val;
 
    sgn = 1;
    for (firstDigit = false, val = 0, i = 0;;) {
        c = cptr[i++];
        if (base == 256) {
            if (!c) break;
            if (c == '\'') {
                ++i;
                break;
            }
            val *= base;
            val += c;
            continue;
        }
        if (c == '-') {
            if (firstDigit) break;
            if (sgn == -1)  break;
            sgn = -1;
            continue;
        }
        if (c == '$') {
            if (firstDigit) break;
            base = 16;
            continue;
        }
        if (gHandleChars) {
            if (c == '\'') {
                if (firstDigit) break;
                base = 256;
                continue;
            }
        }
        if (base == 10) {
            if (c < '0') break;
            if (c > '9') break;
        }
        if ((!firstDigit) && (c == ' ')) continue;
        c -= '0';
        if (base == 16) {
            if (c > 16) c -= 7;     /* Make 'A' a 10, etc. */
            if (c > 32) c -= 32;    /* Make lower-case upper-case. */
        }
        if (c < 0) break;
        if (c >= base) break;
        val *= base;
        val += (c * sgn);
        firstDigit = true;
    }
 
    if (charsUsed) *charsUsed = --i;
 
    gBase = base;
    return(val);
}
 
 
 
/*****************************************************************************/
 
 
 
short   GetLastBase(Boolean handleChars)
{
    gHandleChars = handleChars;
    return(gBase);
}
 
 
 
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
 
 
 
/* Catenate a single character multiple times onto the designated string. */
 
void    pcatchr(StringPtr pptr, char c, short count)
{
    while (count--) pptr[++(pptr[0])] = c;
}
 
 
 
/*****************************************************************************/
 
 
 
void    pcatpaddec(StringPtr pptr, char padChr, short minApnd, short maxApnd, long v)
{
    pcatpadnum(pptr, padChr, minApnd, maxApnd, v, -10);
}
 
void    pcatdec(StringPtr pptr, long v)
{
    pcatnum(pptr, v, -10);
}
 
 
 
/*****************************************************************************/
 
 
 
void    pcatpadhex(StringPtr pptr, char padChr, short minApnd, short maxApnd, long v)
{
    char    str[33];
 
    ccpypadhex(str, padChr, minApnd, maxApnd, v);
    c2p(str);
    pcat(pptr, (StringPtr)str);
}
 
void    pcathex(StringPtr pptr, long v)
{
    pcatpadhex(pptr, 0, 0, 8, v);
}
 
 
 
/*****************************************************************************/
 
 
 
long    pcatnum(StringPtr pptr, long v, short base)
{
    unsigned long   j, vv;
 
    vv = v;
    if (base < 0) {
        base = -base;
        if (v < 0) {
            pptr[++*pptr] = '-';
            vv = -vv;
        }
    }
    j = 0;
    if (vv >= base)
        j = pcatnum(pptr, vv / base, base);
 
    pptr[++*pptr] = "0123456789ABCDEF"[vv - j];
    return(base * vv);
}
 
void    pcatpadnum(StringPtr pptr, char padChr, short minApnd, short maxApnd, long v, short base)
{
    Str32   str;
 
    pcpynum(str, v, base);      /* Generate minimum-digit hex value. */
 
    if (str[0] > maxApnd) str[0] = maxApnd;
 
    if (str[0] < minApnd)
        if (padChr)
            pcatchr(pptr, padChr, (minApnd - str[0]));
                /* if we have a pad character, and if necessary, pad the string. */
 
    pcat(pptr, str);            /* Add the hex digits to the string. */
}
 
 
 
/*****************************************************************************/
 
 
 
void    pcpychr(StringPtr pptr, char c, short count)
{
    pptr[0] = 0;
    pcatchr(pptr, c, count);
}
 
 
 
/*****************************************************************************/
 
 
 
void    pcpypaddec(StringPtr pptr, char padChr, short minApnd, short maxApnd, long v)
{
    *pptr = 0;
    pcatpaddec(pptr, padChr, minApnd, maxApnd, v);
}
 
void    pcpydec(StringPtr pptr, long v)
{
    *pptr = 0;
    pcatdec(pptr, v);
}
 
 
 
/*****************************************************************************/
 
 
 
void    pcpypadnum(StringPtr pptr, char padChr, short minApnd, short maxApnd, long v, short base)
{
    *pptr = 0;
    pcatpadnum(pptr, padChr, minApnd, maxApnd, v, base);
}
 
void    pcpynum(StringPtr pptr, long v, short base)
{
    *pptr = 0;
    pcatnum(pptr, v, base);
}
 
 
 
/*****************************************************************************/
 
 
 
void    pcpypadhex(StringPtr pptr, char padChr, short minApnd, short maxApnd, long v)
{
    *pptr = 0;
    pcatpadhex(pptr, padChr, minApnd, maxApnd, v);
}
 
void    pcpyhex(StringPtr pptr, long v)
{
    pcpypadhex(pptr, 0, 0, 8, v);
}
 
 
 
/*****************************************************************************/
 
 
 
long    p2dec(StringPtr pptr, short *charsUsed)
{
    return(p2num(pptr, 10, charsUsed));
}
 
 
 
/*****************************************************************************/
 
 
 
long    p2hex(StringPtr pptr, short *charsUsed)
{
    return(p2num(pptr, 16, charsUsed));
}
 
 
 
/*****************************************************************************/
 
 
 
long    p2num(StringPtr pptr, short base, short *charsUsed)
{
    long    val;
 
    p2c(pptr);
    val = c2num((char *)pptr, base, charsUsed);
    c2p((char *)pptr);
    return(val);
}
 
 
 
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
 
 
 
short   GetHexByte(char *cptr)
{
    short   val, i, chr;
 
    for (val = 0, i = 0; i < 2; ++i) {
        chr = cptr[i];
        if (chr == '=') return(cptr[++i]);
        if (chr == 'Å') {
            chr = cptr[++i];
            if ((chr >= 'a') && (chr <= 'z')) chr -= 32;
            return(chr);
        }
        if (chr > 'F')
            chr -= 0x20;
        if (chr > '9')
            chr -= ('A' - '9' - 1);
        val = (val << 4) + chr - '0';
    }
    return(val);
}
 
 
 
/*****************************************************************************/
 
 
 
Boolean EqualHandle(void *h1, void *h2)
{
    long    s1, s2;
    Ptr     p1, p2;
 
    if ((h1) && (!h2)) return(false);
    if ((h2) && (!h1)) return(false);
    if ((s1 = GetHandleSize(h1)) != (s2 = GetHandleSize(h2))) return(false);
 
    p1 = *(Handle)h1;
    p2 = *(Handle)h2;
    for (s1 = 0; s1 < s2; ++s1)
        if (p1[s1] != p2[s1]) return(false);
        
    return(true);
}
 
 
 
/*****************************************************************************/
 
 
 
Boolean EqualData(void *v1, void *v2, long size)
{
    Ptr     p1, p2;
    long    ii;
 
    if ((v1) && (!v2)) return(false);
    if ((v2) && (!v1)) return(false);
 
    p1 = (Ptr)v1;
    p2 = (Ptr)v2;
    for (ii = 0; ii < size; ++ii)
        if (p1[ii] != p2[ii]) return(false);
        
    return(true);
}
 
 
 
/*****************************************************************************/
 
 
 
void    SetMem(void *vptr, unsigned char c, unsigned long len)
{
    Ptr ptr;
 
    ptr = (Ptr)vptr;
    while (len--) *ptr++ = c;
}
 
 
 
/*****************************************************************************/
 
 
 
OSErr   HInsert(Handle hh, long offset, void *dataptr, long delta);
OSErr   HInsert(Handle hh, long offset, void *dataptr, long delta)
{
    long    dataSize;
    char    *cptr;
    OSErr   err;
 
    dataSize = GetHandleSize(hh);
 
    if (!(delta & 0x80000000L)) {
        SetHandleSize(hh, dataSize + delta);
        err = MemError();
        if (err) return(err);
    }
    else {
        offset -= delta;
            /* We are removing what we are pointing/offset at, so the block that is to be moved is
            ** after the data being removed at the offset.  The size of the data being removed is
            ** i-delta, so therefore subtract this negative number from offset to skip past data. */
    }
 
    cptr = (*(char **)hh) + offset;
    BlockMove(cptr, cptr + delta, dataSize - offset);
 
    if (delta & 0x80000000L) {
        SetHandleSize(hh, dataSize + delta);
            /* Delta is negative -- we are deleting data.  dataptr is unused. */
    }
    else {
        cptr = (*(char **)hh) + offset;
        BlockMove(dataptr, cptr, delta);
            /* Delta is positive -- we are adding data pointed at by dataptr. */
    }
 
    return(noErr);
}