StringUtils.c

/*
    File:       StringUtils.c
 
    Contains:   
 
    Written by:     
 
    Copyright:  Copyright © 1988-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source 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 source
                code, but that you've made changes.
 
    Change History (most recent first):
                7/22/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
 
#ifndef __MEMORY__
#include <Memory.h>
#endif
 
#ifndef __STRINGUTILS__
#include "StringUtils.h"
#endif
 
#ifndef __COMPENV__
#include "CompEnv.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;
 
 
 
/*****************************************************************************/
/*****************************************************************************/
 
#ifdef applec
#pragma segment ATGStringUtils
#endif
 
/*****************************************************************************/
/*****************************************************************************/
 
 
 
/* 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);
}