Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
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); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-07-22