/* Copyright (c) 2017, Computer History Museum All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) 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. * Neither the name of Computer History Museum nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. 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 HOLDER OR CONTRIBUTORS 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. */ #define FILE_NUM 73 /* Copyright (c) 1995 by QUALCOMM Incorporated */ #include "stringutil.h" #pragma segment StringUtil PStr FormatString(unsigned int arg, PStr string, short format, short digits); Boolean PPtrMatchLWSPSpot(PStr look,Ptr text,uLong textLen,UPtr *matchEnd); /************************************************************************ * AllDigits - is a string made up only of digits? ************************************************************************/ Boolean AllDigits(UPtr s, long len) { while (len && '0'<=*s && *s<='9') {s++;len--;} return(len==0); } /************************************************************************ * HighBits - count high bits in a string ************************************************************************/ long HighBits(UPtr s,long len) { long count = 0; while (len-->0) if (*s++>127) count++; return count; } /********************************************************************** * BeginsWith - does one string begin with another? **********************************************************************/ Boolean BeginsWith(PStr string,PStr prefix) { uShort size; Boolean result; if (*string<*prefix) return(False); size = *string; *string = *prefix; result = StringSame(string,prefix); *string = size; return(result); } /********************************************************************** * CaptureHex - read hex strings **********************************************************************/ void CaptureHex(PStr from,PStr to) { Str255 scratch; long len; len = *from; CaptureHexPtr(from+1,scratch+1,&len); *scratch = len; PCopy(to,scratch); } /********************************************************************** * CaptureHexPtr - read hex strings **********************************************************************/ void CaptureHexPtr(Ptr from,Ptr to,long *pLen) { UPtr spot,end; UPtr toSpot,toEnd; spot = from; end = from+*pLen; toSpot = to; toEnd = to+*pLen; for (;spot=*prefix && !striscmp(name+1,prefix+1); } /************************************************************************ * StartsWithPtr - does a string start with a prefix? ************************************************************************/ Boolean StartsWithPtr(UPtr name,uLong len,PStr prefix) { return len>=*prefix && !strincmp(name,prefix+1,*prefix); } /************************************************************************ * EqualStrRes - is a string the same as a resource? ************************************************************************/ Boolean EqualStrRes(PStr string, short resId) { Str255 s; return(StringSame(GetRString(s,resId),string)); } /************************************************************************ * EscapeChars - escape characters in a string ************************************************************************/ PStr EscapeChars(PStr string, PStr toEscape) { Str255 scratch; UPtr to = scratch+1; UPtr from = string+1; UPtr end = string+*string+1; Boolean escaped = False; while (from' ' && *spot!=lowerDelta) || (*spot==' ' && spot!=(end-1))) *toSpot++ = *spot; else { *toSpot++ = lowerDelta; Bytes2Hex(spot,1,toSpot); toSpot += 2; } } *scratch = toSpot - scratch - 1; PCopy(to,scratch); } /********************************************************************** * Transmogrify - change one string into another, using two STR# for xlation **********************************************************************/ PStr Transmogrify(PStr toStr,short toId,PStr fromStr,short fromId) { short index; if (index=FindSTRNIndex(fromId,fromStr)) GetRString(toStr,toId+index); else if (toStr!=fromStr) PCopy(toStr,fromStr); return(toStr); } /************************************************************************ * FixNewlines - remove cr, and turn nl into cr ************************************************************************/ void FixNewlines(UPtr string,long *count) { char *from, *to; long n; for (to=from=string,n= *count;n;n--,from++) if (*from=='\012') *to++ = '\015'; else if (*from!='\015') *to++ = *from; *count = to-string; } /********************************************************************** * **********************************************************************/ PStr FormatString(unsigned int arg, PStr string, short format,short digits) { short n; struct hostInfo hi; *string = 0; switch (format) { case 'c': string[0] = 1; string[1] = arg; break; case 's': *string = strlen((UPtr)arg); *string = MIN(*string,253); BMD((UPtr)arg,string+1,*string); break; case 'p': PCopy(string,(PStr)arg); break; case 'e': PCopy(string,(PStr)arg); EscapeInHex(string,string); break; case 'i': NumToDot(arg,string); break; case 'I': if (!GetHostByAddr(&hi,arg)) { *string = strlen(hi.cname); BMD(hi.cname,string+1,*string); } else { NumToDot(arg, string+1); string[0] = string[1]+2; string[1] = '['; string[string[0]] = ']'; } break; case 'd': NumToString(arg,string); break; case 'K': if (arg<1 K) NumToString(arg,string); else if (arg < 10 K) { arg *= 10; arg /= 1 K; if (arg%10) ComposeString(string,"\p%d.%dK",arg/10,arg%10); else ComposeString(string,"\p%dK",arg/10); } else if (arg < 1 K K) { arg /= 1 K; NumToString(arg,string); PCatC(string,'K'); } else if (arg < 10 K K) { arg *= 10; arg /= 1 K K; if (arg%10) ComposeString(string,"\p%d.%dM",arg/10,arg%10); else ComposeString(string,"\p%dM",arg/10); } else { arg /= 1 K K; NumToString(arg,string); PCatC(string,'M'); } break; case 'q': Quote822(string,(UPtr)arg,True); break; case 'r': GetRString(string,arg); break; case 'b': n = *string = 32; for (string++;n;string++) { *string = arg&(1<<31) ? '1' : '0'; arg <<= 1; n--; } break; case 'x': Long2Hex(string,arg); if (digits) { while (*stringdigits) { BMD(string+1+(*string-digits),string+1,digits); *string = digits; } } break; case '#': GetRString(string,PluralStrn+(arg==1?1:2)); break; case '$': GetRString(string,PluralStrn+(arg==1?3:4)); break; case '&': GetRString(string,PluralStrn+(arg==1?5:6)); break; case '*': GetRString(string,PluralStrn+(arg==1?7:8)); break; case 'O': *string = 6; string[1] = string[6] = '\''; string[2] = ((Uptr)&arg)[0]; string[3] = ((Uptr)&arg)[1]; string[4] = ((Uptr)&arg)[2]; string[5] = ((Uptr)&arg)[3]; break; case 'o': *string = 4; string[1] = ((Uptr)&arg)[0]; string[2] = ((Uptr)&arg)[1]; string[3] = ((Uptr)&arg)[2]; string[4] = ((Uptr)&arg)[3]; break; case 'B': if (arg) PCopy(string,"\pTRUE"); else PCopy(string,"\pFALSE"); break; } return(string); } /************************************************************************ * LCD - find the least common denom of two strings ************************************************************************/ PStr LCD(PStr s1,PStr s2) { UPtr p1,p2,end; char c1,c2; end = s1+MIN(*s1,*s2)+1; for (p1=s1+1,p2=s2+1;p1string;spot--) if (*spot==c) return(spot); return(nil); } /********************************************************************** * PInsert - insert some text **********************************************************************/ PStr PInsert(PStr string,short size,PStr insert,UPtr spot) { short toInsert = MIN(*insert,size-*string-1); if (toInsert>0) { BMD(spot,spot+toInsert,*string-(spot-string-1)); BMD(insert+1,spot,toInsert); *string += toInsert; } return(string); } /********************************************************************** * PInsertC - insert a single character **********************************************************************/ PStr PInsertC(PStr string,short size,Byte c,UPtr spot) { Str15 s; *s = 1; s[1] = c; return(PInsert(string,size,s,spot)); } /************************************************************************ * PLCat - concat a long onto a string (preceed it with a space) ************************************************************************/ UPtr PLCat(UPtr string,long num) { short n; /* length of old string + 1 */ n = *string+1; NumToString(num,string+n); string[0] += string[n]+1; string[n] = ' '; return(string); } /************************************************************************ * PXCat - concat a long onto a string in hex ************************************************************************/ UPtr PXCat(UPtr string,long num) { Str31 x; Bytes2Hex((void*)&num,sizeof(long),x+1); *x = 8; return(PCat(string,x)); } /************************************************************************ * PXWCat - concat a short onto a string in hex ************************************************************************/ UPtr PXWCat(UPtr string,short num) { Str31 x; Bytes2Hex((void*)&num,sizeof(short),x+1); *x = 4; return(PCat(string,x)); } /************************************************************************ * Tr - translate text in a handle ************************************************************************/ Boolean Tr(Handle text,Uptr fromS, Uptr toS) { long len = GetHandleSize(text); return(TrLo(*text,len,fromS,toS)); //no handle lock; keep in segment with TrLo } /************************************************************************ * TrLo - translate text in a pointer ************************************************************************/ Boolean TrLo(UPtr text,long len,Uptr fromS, Uptr toS) { UPtr end,spot; Boolean did=False; short fromChar,toChar; end = text+len; for (;*fromS;fromS++,toS++) { fromChar = *fromS; toChar = *toS; for (spot=text;spot=subEnd) return(stringSpot-*sub); string++; } return(nil); } /************************************************************************ * PReplace - replace one string with another ************************************************************************/ PStr PReplace(PStr string,PStr find,PStr replace) { UPtr spot; if (*find && !EqualString(find,replace,true,true)) while (spot=PFindSub(find,string)) { if (*string+*replace-*find>255) break; BMD(spot+*find,spot+*replace,*string-(spot-string-1)-*find); BMD(replace+1,spot,*replace); *string += *replace-*find; } return(string); } /************************************************************************ * PSCat_C - C routine to concat a string, worrying about length ************************************************************************/ UPtr PSCat_C(PStr string,PStr suffix,short max) { short tot = MIN(max-1,*string+*suffix); short add = tot - *string; if (add>0) { BMD(suffix+1,string+*string+1,add); *string += add; } return(string); } /********************************************************************** * copy a pascal string into a c string **********************************************************************/ UPtr PtoCcpy(UPtr cStr, UPtr pStr) { BMD(pStr+1,cStr,*pStr); cStr[*pStr] = 0; return(cStr); } /********************************************************************** * PStrCopy - copy a pascal string **********************************************************************/ PStr PStrCopy(PStr to,PStr from,short max) { long len = MIN(max,*from+1); // length includes length byte BlockMoveData(from,to,len); *to = len-1; return to; } /********************************************************************** * InfiniteString - set string to all 0xFFs **********************************************************************/ PStr InfiniteString(PStr s,short size) { short i; *s = size-1; for(i=1;i<=size;i++) s[i] = 0xFF; return s; } /************************************************************************ * ItemFromResAppearsInStr - does a string contain an item from a list of * items in a resource ************************************************************************/ Boolean ItemFromResAppearsInStr(short resID,PStr string,UPtr delims) { Str255 s; Str63 token; UPtr spot; //default delimitter is comma if (!delims) delims = ","; GetRString(s,resID); spot = s+1; while (PToken(s,token,&spot,delims)) if (PFindSub(token,string)) return true; return false; } /************************************************************************ * StrIsItemFromRes - is a string one of the items in a resource? ************************************************************************/ Boolean StrIsItemFromRes(PStr string,short resID,UPtr delims) { Str255 s; Str63 token; UPtr spot; //default delimitter is comma if (!delims) delims = ","; GetRString(s,resID); spot = s+1; while (PToken(s,token,&spot,delims)) if (StringSame(token,string)) return true; return false; } /************************************************************************ * PToken - grab a token out of a string * Returns pointer to token argument * Saves state in spotP ************************************************************************/ PStr PToken(PStr string,PStr token,UPtr *spotP,UPtr delims) { UPtr spot; UPtr end = string+*string+1; UPtr tSpot = token+1; *token = 0; if (*spotP>=end) return(nil); for (spot = *spotP; spot=end) return(false); for (spot = *spotP; spot= *re) { /* it's long enough */ reSpot = re+*re; do { reSpot--; colon--; while (reSpot>re && !IsWordChar[*reSpot]) reSpot--; while (colon>string && !IsWordChar[*colon]) colon--; if (colon>string && reSpot>re) if ((*colon & 0x1f)!=(*reSpot&0x1f)) break; } while (colon>string && reSpot>re); if (reSpot!=re) return false; if (colon==string) return true; //ok, we didn't use up all of the subject. See if it's a lyris-type thing MakePStr(remainder,string+1,colon-string+1); TrimAllWhite(remainder); TrimSquares(remainder,true,true); return(*remainder==0); } } } return(False); } /************************************************************************ * TrimSquares - trim square-bracketed stuff from start of string ************************************************************************/ Boolean TrimSquares(PStr s,Boolean multiple,Boolean internal) { Str31 left, right; UPtr spot; Boolean result = false; GetRString(left,SQUARE_LEFT); GetRString(right,SQUARE_RIGHT); TrimInitialWhite(s); if (!internal) { while (*s>2) { if (spot=PIndex(left,s[1])) // left delimiter { if (spot=PIndex(s,right[spot-left])) // found both delimiters! { BMD(spot+1,s+1,*s - (spot-s)); *s -= spot-s; TrimInitialWhite(s); result = true; } else break; // didn't find it } else break; // didn't find it if (!multiple) break; } } else { short brk; UPtr lPtr; UPtr rPtr; for (brk=1;*s>2 && brk<=*left;brk++) { if (lPtr=PIndex(s,left[brk])) if (rPtr=PIndex(s,right[brk])) if (lPtrs+1 && cp<=s+*s) { len = *s - (cp-(s+1)); BMD(cp,s+1,len); *s = len; } return(s); } /********************************************************************** * TrimInternalWhite - collapse internal whitespace into single **********************************************************************/ PStr TrimInternalWhite(PStr s) { Boolean wasWhite = false; Boolean isWhite; char *spot; char *end = s+*s; char *copySpot = s+1; for (spot=s+1;spot<=end;spot++) { isWhite = IsSpace(*spot); if (isWhite && wasWhite) continue; // if both white, skip *copySpot++ = *spot; // otherwise, copy the char wasWhite = isWhite; // remember if we were looking at whitespace } *s = copySpot-s-1; return(s); } /************************************************************************ * TrimPrefix - strip a prefix from a string ************************************************************************/ Boolean TrimPrefix(UPtr string, UPtr prefix) { short oldLen = *string; if (oldLen < *prefix) return(False); *string = *prefix; if (StringSame(string,prefix)) { BMD(string+1+*prefix,string+1,oldLen-*prefix); *string = oldLen - *prefix; return(True); } else { *string = oldLen; return(False); } } /********************************************************************** * StringSame - are two strings the same? **********************************************************************/ Boolean StringSame(PStr s1,PStr s2) { if (*s1!=*s2) return false; // quick test if (FurrinSort) return(!IdenticalString(s1,s2,nil)); else return(EqualString(s1,s2,False,True)); } /********************************************************************** * StringComp - return whether s1s2 (positive) **********************************************************************/ long StringComp(PStr s1,PStr s2) { if (FurrinSort) return(CompareString(s1,s2,nil)); else return(RelString(s1,s2,False,True)); } /********************************************************************** * MyUpperText - uppercase text with or without fancy furrin stuff **********************************************************************/ void MyUpperText(UPtr buffer,long bufferSize) { if (FurrinSort) UppercaseText(buffer,bufferSize,smSystemScript); else { short i; for (i=0;i0;s++) if (!IsWhite(*s)) return false; return true; } /********************************************************************** * IsAllLWSPPtr - is a string all lwsp? **********************************************************************/ Boolean IsAllLWSPPtr(UPtr s,long len) { for (;len-->0;s++) if (!IsLWSP(*s)) return false; return true; } /********************************************************************** * IsAllUpper - is a string all lwsp? **********************************************************************/ Boolean IsAllUpper(PStr s) { UPtr end = s+*s+1; if (!*s) return false; for (s++;s= 0L) { tempChar = *inStr++; if(tempChar & 0x80) { if(tempChar & 0x3C) { *outStr++ = '?'; ++len; while((tempChar <<= 1) & 0x80) { --inLen; ++inStr; } } else { *outStr++ = ((tempChar & 0x03) << 6) + (*inStr & 0x7F); ++len; --inLen; } } else { *outStr++ = tempChar; ++len; } } *outLen = len; } #undef StringToNum void MyStringToNum(PStr string,long *num) { if(!*string || !(isdigit(string[1])||string[1]=='-'||string[1]=='+')) *num=0L; else StringToNum(string,num); } /************************************************************************ * PtrPtrMatchLWSP - match two strings, considering all LWSP as the same ************************************************************************/ Boolean PtrPtrMatchLWSP(Ptr lookFor, short lookLen, Ptr text, uLong textLen, Boolean atStart, Boolean atEnd) { Str255 shortLook; UPtr spot, end; UPtr matchEnd; lookLen = MIN(lookLen,250); // First, copy the string being looked for, collapsing LWSP end = lookFor+lookLen; spot = shortLook+1; while (lookFor