home *** CD-ROM | disk | FTP | other *** search
- /*
- File: CAS_StringTools.c
-
- Contains: Utility routines for strings.
-
- Written by: David H Nelson
-
- Copyright © 1988-1995 ComponentWorks, All rights reserved.
-
- Change History (most recent first):
-
- <1> 1988 DHN Created.
-
- */
-
- #include "CAS_CTools.h"
- #include "CAS_StringTools.h"
-
- static Str63 pluralStr, singularStr;
-
-
- //----------------------------------------------------------------------
- // Convert a C string to a Pascal string
- // Be careful, a routine with the same name exists in LSC 4.0 "CtoPStr:
- StringPtr ctopstr(char *s)
- {
- return((StringPtr) CtoPstr(s));
- }
-
- //----------------------------------------------------------------------
- // Convert a Pascal string to a C string
- // Be careful, a routine with the same name exists in LSC 4.0 "PtoCStr:
- char *ptocstr(Str255 s)
- {
- return(PtoCstr(s));
- }
-
- //----------------------------------------------------------------------
- // Get the individual string from 'STR#' iRedID and item iStringID into the
- // global resStr.
- StringPtr sGetResString(short iResID, short iStringID)
- {
- resStr[0] = 0;
- GetIndString(resStr,iResID,iStringID);
- return(resStr);
- }
-
- //----------------------------------------------------------------------
-
- short iStrPos(register Str255 s, register char c)
- {
- StringPtr s0 = s;
- register StringPtr e;
-
- e = s + (long) *s + 1; // 1 past end of string
- s++;
-
- while ((s < e) && (*s != c)) s++;
-
- return ( (s < e && *s == c) ? s-s0 : -1 );
- }
-
- //----------------------------------------------------------------------
- // convert the character into uppercase if it's an English letter.
- char cUpperCase(register char c)
- {
- return((c > 0x60 && c < 0x7B) ? c-0x20 : c);
- }
-
- //----------------------------------------------------------------------
- // Substitute up to 10 strings into the given string at the ^0 through ^9 positions
- // in the string. All ^X are removed from the string. Nil may be passed for any
- // of the substitution strings.
- StringPtr sParamStr(
- Str255 theStr,
- Str255 s0,
- Str255 s1,
- Str255 s2,
- Str255 s3,
- Str255 s4,
- Str255 s5,
- Str255 s6,
- Str255 s7,
- Str255 s8,
- Str255 s9 )
- {
- Handle hStr;
- Str31 sSearch;
-
- hStr = NewHandle( theStr[0] );
- if (hStr == nil)
- theStr[0] = '\0';
- else
- {
- BlockMoveData( &theStr[1], *hStr, (long)(theStr[0]) );
-
- if (s0 != nil)
- {
- sCopyStr( (StringPtr)"\p^0", sSearch );
- Munger( hStr, 0L, &sSearch[1], sSearch[0], &s0[1], s0[0] );
- }
-
- if (s1 != nil)
- {
- sCopyStr( (StringPtr)"\p^1", sSearch );
- Munger( hStr, 0L, &sSearch[1], sSearch[0], &s1[1], s1[0] );
- }
-
- if (s2 != nil)
- {
- sCopyStr( (StringPtr)"\p^2",sSearch);
- Munger( hStr, 0L, &sSearch[1], sSearch[0], &s2[1], s2[0] );
- }
-
- if (s3 != nil)
- {
- sCopyStr( (StringPtr)"\p^3",sSearch);
- Munger( hStr, 0L, &sSearch[1], sSearch[0], &s3[1],s3[0] );
- }
-
- if (s4 != nil)
- {
- sCopyStr( (StringPtr)"\p^4", sSearch );
- Munger( hStr, 0L, &sSearch[1], sSearch[0], &s4[1],s4[0] );
- }
-
- if (s5 != nil)
- {
- sCopyStr( (StringPtr)"\p^5", sSearch );
- Munger( hStr, 0L, &sSearch[1], sSearch[0] ,&s5[1], s5[0] );
- }
-
- if (s6 != nil)
- {
- sCopyStr( (StringPtr)"\p^6", sSearch );
- Munger( hStr, 0L, &sSearch[1], sSearch[0], &s6[1], s6[0] );
- }
-
- if (s7 != nil)
- {
- sCopyStr( (StringPtr)"\p^7", sSearch );
- Munger( hStr, 0L, &sSearch[1], sSearch[0], &s7[1], s7[0] );
- }
-
- if (s8 != nil)
- {
- sCopyStr( (StringPtr)"\p^8", sSearch );
- Munger( hStr, 0L, &sSearch[1], sSearch[0], &s8[1], s8[0] );
- }
-
- if (s9 != nil)
- {
- sCopyStr( (StringPtr)"\p^9", sSearch );
- Munger( hStr, 0L, &sSearch[1], sSearch[0], &s9[1], s9[0] );
- }
-
- theStr[0] = min( 255, GetHandleSize( hStr ) );
- BlockMoveData( *hStr, &theStr[1], (long)(theStr[0]) );
-
- DisposeHandle( hStr );
- }
-
- return theStr;
- }
-
- //----------------------------------------------------------------------
- // convert the number (in seconds) to a string of the form 'about X minutes', or…
- // 'about a minute' or 'less than a minute'
- void NumToEstimatedTimeString(long TimeLeft,Str63 sTimeLeft)
- {
- Str63 sMinutes;
-
- if (TimeLeft < 45)
- {
- GetIndString(sTimeLeft,CStringsID,38); // less than a minute
- return;
- }
-
- if (TimeLeft < 90)
- {
- GetIndString( sTimeLeft, CStringsID, 39 ); // about a minute
- return;
- }
-
- NumToThousandString( (TimeLeft+30) / 60,sMinutes );
-
- GetIndString( sTimeLeft, CStringsID, 40 ); // about ^0 minutes
- sParamStr( sTimeLeft, sMinutes, nil, nil, nil, nil, nil, nil, nil, nil, nil);
- }
-
- //----------------------------------------------------------------------
- // convert the number (in seconds) to a string of the form 'HH:MM:SS'
- void NumToTimeLeftString(
- long TimeLeft,
- Str63 sTimeLeft )
- {
- Str63 sMinutes, sSeconds;
- short Hours, Minutes, Seconds;
-
- Hours = TimeLeft / (60*60);
- Minutes = (TimeLeft / 60) % 60;
- Seconds = TimeLeft % 60;
-
- NumToString( (long)Hours, sTimeLeft );
- NumToString( (long)Minutes, sMinutes );
- NumToString( (long)Seconds, sSeconds );
-
- if (sMinutes[0] < 2)
- { // only 1 digit?
- sMinutes[2] = sMinutes[1];
- sMinutes[1] = '0'; // put in leading zero on minutes
- sMinutes[0] = 2;
- }
-
- while (sSeconds[0] < 2)
- { // only 1 digit?
- sSeconds[2] = sSeconds[1];
- sSeconds[1] = '0'; // put in leading zero on seconds
- sSeconds[0] = 2;
- }
-
- sTimeLeft[++sTimeLeft[0]] = ':';
- sTimeLeft[++sTimeLeft[0]] = sMinutes[1];
- sTimeLeft[++sTimeLeft[0]] = sMinutes[2];
- sTimeLeft[++sTimeLeft[0]] = ':';
- sTimeLeft[++sTimeLeft[0]] = sSeconds[1];
- sTimeLeft[++sTimeLeft[0]] = sSeconds[2];
-
- }
-
- //----------------------------------------------------------------------
- // convert the number into a string (0-9) with the current int'l seperator at each
- // third digit.
- void NumToThousandString(long theLong,Str63 sThousandString)
- {
- char theSep;
- Intl0Hndl theIntl0Hndl;
- short i, j;
-
- NumToString(theLong,sThousandString);
-
- theIntl0Hndl = (Intl0Hndl)IUGetIntl(0);
- theSep = (**(Intl0Hndl)(IUGetIntl(0))).thousSep;
-
- i = sThousandString[0];
- while (i>3)
- {
- i -= 2;
- for (j = sThousandString[0]++; j >= i ; j--)
- sThousandString[j+1] = sThousandString[j];
-
- sThousandString[i--] = theSep;
- }
- }
-
- //----------------------------------------------------------------------
- // convert the string of numbers (0-9 with embedded commas) into a number
- void ThousandStringToNum(Str63 sThousandString, long *theLong)
- {
- char theChar;
- short i,j;
- Str63 s0;
-
- sCopyStr(sThousandString, s0);
-
- i = s0[0];
- while (i>0)
- {
- theChar = s0[i];
- if (theChar < '0' || theChar > '9')
- {
- j = i;
- while (j<s0[0])
- {
- s0[j] = s0[j+1];
- j++;
- }
- s0[0]--;
- }
- i--;
- }
- StringToNum(s0, theLong);
- }
-
- //----------------------------------------------------------------------
- // convert theLong into a string of numbers rounded to the nearest 1K with the current
- // int'l seperator at each third digit.
- void NumToKString(long theLong, Str63 sKString)
- {
- // char theSep;
-
- theLong += 1023; // round up
-
- theLong >>= 10;
-
- NumToThousandString(theLong, sKString);
- #if 0
- theIntl0Hndl = (Intl0Hndl)IUGetIntl(0);
- theSep = (**theIntl0Hndl).thousSep;
-
- i = sKString[0];
- while (i>3)
- {
- i -= 2;
- for (j = sKString[0]++; j >= i ; j--)
- {
- sKString[j+1] = sKString[j];
- }
- sKString[i--] = theSep;
- }
- #endif
- }
-
- #if false
- //----------------------------------------------------------------------
- // convert theLong into a string rounded to the nearest .5K
- void NumToKString(long theLong,Str63 sThousandString)
- {
- Intl0Hndl theIntl0Hndl;
- short i,j;
- long saveLong;
-
- theLong += 511; // round up
-
- saveLong = theLong>>9;
-
- theLong >>= 10;
-
- NumToString(theLong,sThousandString);
-
- theIntl0Hndl = (Intl0Hndl)IUGetIntl(0);
- theSep = (**theIntl0Hndl).thousSep;
-
- i = sThousandString[0];
- while (i > 3)
- {
- i -= 2;
- for (j = sThousandString[0]++; j >= i ; j--)
- {
- sThousandString[j+1] = sThousandString[j];
- }
- sThousandString[i--] = theSep;
- }
- // if it's zero, leave it.
- // if it's between one and 511 make append '.5'
- // otherwise round it to the nearest .5K
- if (saveLong && (max(1,saveLong) & 0x1))
- {
- sThousandString[++sThousandString[0]] = (**theIntl0Hndl).decimalPt;
- sThousandString[++sThousandString[0]] = '5';
- }
- }
- #endif
-
- //----------------------------------------------------------------------
- // convert theLong into a string (0-9) rounded to the nearest byte, KB, or MB
- // with the current int'l seperator at each third digit.
- void NumToSizeString(long theLong, Str63 sSizeString)
- {
- Str63 s0;
-
- if (theLong < 1024L)
- {
- GetIndString(sSizeString, sizeStrings, inByteSize);
- }
- else if (theLong < 1048576L) // convert to nearest KB
- {
- theLong += 1023; // round up to nearest KB
- theLong >>= 10;
-
- GetIndString(sSizeString, sizeStrings, inKBSize);
- }
- else // convert to nearest MB
- {
- theLong += 1048576; // round up to next MB
- theLong >>= 20;
-
- GetIndString(sSizeString, sizeStrings, inMBSize);
- }
-
- NumToThousandString( theLong, s0 );
- sParamStr( sSizeString, s0, nil, nil, nil, nil, nil, nil, nil, nil, nil );
- }
-
- //----------------------------------------------------------------------
- // return a pointer to a null Pascal string.
- StringPtr sNullStr( void )
- {
- return (StringPtr)"\p";
- }
-
- //----------------------------------------------------------------------
- // copy the Pascal string pointed to by sSrc to the pascal string pointed to by sDst
- StringPtr sCopyStr(
- StringPtr sSrc,
- StringPtr sDst )
- {
- #ifndef _68000_
- register short i = sSrc[0];
- register StringPtr sDst2 = sDst;
-
- do
- *sDst2++ = *sSrc++;
- while (i--);
- #else
- asm
- {
- move.l sSrc,a0
- move.l sDst,a1
- clr.w d0
- move.b (a0),d0
- @loop move.b (a0)+,(a1)+
- dbf d0,@loop
- }
- #endif
- return(sDst);
- }
-
- //----------------------------------------------------------------------
- // clear the iLength characters (starting with the length byte) of the (Pascal) string sSrc.
- StringPtr sClearStr(Str255 sSrc,short iLength)
- {
- #ifndef _68000_
- while (iLength--)
- *(sSrc++) = 0;
- #else
- asm
- {
- moveq.l #0,d0
- move.l d0,d1
- move.l sSrc,a0
- move.w iLength,d0
- @loop move.b d1,(a0)+
- dbf d0,@loop
- }
- #endif
- return(sSrc);
- }
-
- //----------------------------------------------------------------------
- // append the Pascal string sSrc to the Pascal string sDst.
- StringPtr sAppendStr(StringPtr sSrc, StringPtr sDst)
- {
- #ifndef _68000_
- register short i;
- register StringPtr sDst2;
-
- sDst2 = sDst + *sDst + 1;
- *sDst += i = *sSrc++;
- while (i--)
- *sDst2++ = *sSrc++;
- #else
- asm
- {
- move.l sSrc,a0
- clr.w d0
- move.b (a0)+,d0
- beq @done
- move.l sDst,a1
- clr.w d1
- move.b (a1),d1
- add.b d0,(a1)+
- add.w d1,a1
- @loop move.b (a0)+,(a1)+
- dbf d0,@loop
- @done:
- }
- #endif
- return(sDst);
- }
-
- //----------------------------------------------------------------------
- // copy the string sSrc into the string sDst and make it fit in iMaxWidth pixels
- // using the current font, size, and style by trimming characters and replacing
- // with and elipsis '…'.
- StringPtr sTrimText(StringPtr sSrc,StringPtr sDst,register short iMaxWidth)
- {
- #if 1
- // if (StringWidth(sCopyStr(sSrc,sDst)) > iMaxWidth)
-
- sCopyStr(sSrc,sDst);
- if (TextWidth(sDst+1, 0, sDst[0]) > iMaxWidth)
- {
- sDst[sDst[0]] = '…';
- // while (sDst[0] > 1 && StringWidth(sDst) > iMaxWidth)
- while (sDst[0] > 1 && TextWidth(sDst+1, 0, sDst[0]) > iMaxWidth)
- {
- sDst[--sDst[0]] = '…';
- }
- }
- return(sDst);
- #else
- // This is the int'l utils version.
- sCopyStr(sSrc, sDst);
- TruncString(iMaxWidth, sDst, smTruncEnd);
- #endif
- }
-
- //----------------------------------------------------------------------
- StringPtr sFilterStr(StringPtr sSrc,StringPtr sDst)
- {
- #ifndef _68000_
-
- // $$$$$ must write this in C if it's needed
- //#error sFilterStr not written in C yet.
- DebugStr("\p sFilterStr: not written in C yet.");
-
- #else
- asm
- {
- move.l sSrc,a0
- move.l sDst,a1
- clr.w d1
- move.b (a0)+,d1
- move.b d1,(a1)+
- subq.w #1,d1
- @loop move.b 0(a0,d1.w),d0
- cmpi.b #' ',d0
- bcs @bad
- cmpi.b #0xAD,d0
- beq @bad
- cmpi.b #0xB0,d0
- bcs @good
- cmpi.b #0xB4,d0
- beq @good
- cmpi.b #0xBB,d0
- bcs @bad
- cmpi.b #0xBD,d0
- beq @bad
- cmpi.b #0xC2,d0
- bcs @good
- cmpi.b #0xC7,d0
- bcs @bad
- cmpi.b #0xD6,d0
- beq @bad
- cmpi.b #0xD9,d0
- bcs @good
- @bad move.b #'.',d0
- @good move.b d0,0(a1,d1.w)
- dbf d1,@loop
- move.l sDst,d0
- }
- #endif
- }
-
- //----------------------------------------------------------------------
- // convert the char into hex and append to the string sDst.
- StringPtr sAppendHexChar(char c0,StringPtr sDst)
- {
- #ifndef _68000_
-
- // $$$$$ must write this in C if it's needed
- //#error sAppendHexChar not written in C yet.
- DebugStr("\p sAppendHexChar: not written in C yet.");
-
- #else
- asm
- {
- move.l sDst,a0
- clr.w d0
- move.b (a0),d0
- move.b c0,d1
- lsr.b #4,d1
- ori.b #'0',d1
- cmpi.b #'9'+1,d1
- bcs @1
- addi.b #7,d1
- @1 move.b d1,1(a0,d0.w)
- move.b c0,d1
- andi.b #0xf,d1
- ori.b #'0',d1
- cmpi.b #'9'+1,d1
- bcs @2
- addi.b #7,d1
- @2 move.b d1,2(a0,d0.w)
- addq.b #2,(a0)
- move.l sDst,d0
- }
- #endif
- }
-
- //----------------------------------------------------------------------
- // convert the short into hex and append to the string sDst.
- StringPtr sAppendHexShort(short i0,StringPtr sDst)
- {
- return(sAppendHexChar((char) i0,sAppendHexChar((char) (i0 >> 8),sDst)));
- }
-
- //----------------------------------------------------------------------
- // convert the long into hex and append to the string sDst.
- StringPtr sAppendHexLong(long l0,StringPtr sDst)
- {
- return(sAppendHexShort((short) l0,sAppendHexShort((short) (l0 >> 16),sDst)));
- }
-
- //----------------------------------------------------------------------
- // convert lLength bytes of the data at pBuffer to hex and append to the string sDst.
- StringPtr sAppendHexToStr(StringPtr sDst,Ptr pBuffer,long lLength)
- {
- while (lLength--)
- sAppendHexChar(*pBuffer++,sDst);
- return(sDst);
- }
-
- //----------------------------------------------------------------------
- // convert lLength bytes of the data at pBuffer into the hex string sDst.
- StringPtr sHexToStr(StringPtr sDst,Ptr pBuffer,long lLength)
- {
- sDst[0] = 0;
- return (sAppendHexToStr(sDst,pBuffer,lLength));
- }
-
- //----------------------------------------------------------------------
- // if true, return the C String to append to make an English word plural.
- // if false, return the C String to append to make an English word singular.
- Ptr pPluralStrC(Boolean bPlural)
- {
- GetIndString(pluralStr,CStringsID,41); // 's'
- ptocstr(pluralStr);
- GetIndString(singularStr,CStringsID,42); // ''
- ptocstr(singularStr);
- return (bPlural ? (Ptr) pluralStr : (Ptr) singularStr);
- }
-
- //----------------------------------------------------------------------
- // if true, return the Pascal string to append to make an English word plural.
- // if false, return the Pascal string to append to make an English word singular.
- StringPtr sPluralStr(Boolean bPlural)
- {
- GetIndString(pluralStr,CStringsID,41); // 's'
- GetIndString(singularStr,CStringsID,42); // ''
- return (bPlural ? pluralStr : singularStr);
- }
-
- //----------------------------------------------------------------------
- // Compare the 2 strings and return true if they are the same, false if not.
- Boolean bStrCmp(StringPtr src,StringPtr dst)
- {
- short i;
-
- if (src == dst)
- return true;
-
- for (i=0; i <= src[0]; i++)
- if (src[i] != dst[i])
- return false;
-
- return true;
- }
-
- //----------------------------------------------------------------------
- Boolean bCStrCmp(char *src,char *dst)
- {
- if (src == dst)
- return true;
-
- while (true)
- {
- if (*src != *dst)
- return false;
-
- if (*src == '\0')
- return true;
-
- src++;
- dst++;
- }
-
- return (*src == *dst);
- }
-
- #if 0
- //----------------------------------------------------------------------
- sPrependStr(sSrc,sDst)
- {
- BlockMoveData( sDst+1, sDst+1+sSrc[0], sDst[0] );
- BlockMoveData( sSrc+1, sDst+1, sSrc[0] );
- sDst[0] += sSrc[0];
- }
- #endif
-
- //----------------------------------------------------------------------
- // iJust from GetSysJust(), 0 for left justified, -1 for right justified.
- void drawInfoLine(StringPtr sField, StringPtr sValue, short iJust)
- {
- GrafPtr ourPort;
- Point pStart;
- Style stFace;
-
- GetPort(&ourPort);
-
- GetPen(&pStart); // save the current pen location.
- stFace = ourPort->txFace; // save the current style
-
- TextFace(bold);
- MoveTo(pStart.h - ((iJust ? -1 : 1) * TextWidth(sField+1, 0, sField[0])), pStart.v);
- DrawString(sField);
- TextFace(stFace);
-
- MoveTo(pStart.h + ((iJust ? -1 : 1) * 6), pStart.v);
- DrawString(sValue);
-
- TextFace(stFace); // restore the style
- MoveTo(pStart.h, pStart.v); // restore the pen location.
- }
-
- //----------------------------------------------------------------------
- void drawRJInfoLine(StringPtr sField,StringPtr sValue)
- {
- GrafPtr ourPort;
- Point pStart;
- short iFont, iSize;
- Style stFace;
-
- GetPort(&ourPort);
-
- GetPen(&pStart);
-
- iFont = ourPort->txFont;
- iSize = ourPort->txSize;
- stFace = ourPort->txFace;
-
- TextFace(bold);
- MoveTo(pStart.h-TextWidth(sField+1, 0, sField[0])-4, pStart.v);
- // MoveTo(pStart.h-StringWidth(sField)-4, pStart.v);
- DrawString(sField);
- TextFace(stFace);
-
- MoveTo(pStart.h+68-TextWidth(sValue+1, 0, sValue[0]), pStart.v);
- // MoveTo(pStart.h+68-StringWidth(sValue), pStart.v);
- DrawString(sValue);
-
- TextFont(iFont);
- TextSize(iSize);
- TextFace(stFace);
-
- MoveTo(pStart.h,pStart.v);
- }
-
-