strings.c

Go to the documentation of this file.
00001 
00002 /*  $Id: strings.c 1349 2006-05-04 18:21:50Z sethdill $    */
00003 
00004 /******************************************************************************
00005 
00006     UserLand Frontier(tm) -- High performance Web content management,
00007     object database, system-level and Internet scripting environment,
00008     including source code editing and debugging.
00009 
00010     Copyright (C) 1992-2004 UserLand Software, Inc.
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 
00026 ******************************************************************************/
00027 
00028 #include "frontier.h"
00029 #include "standard.h"
00030 
00031 #ifdef WIN95VERSION
00032     #include "FrontierWinMain.h"
00033 #endif
00034 
00035 #include "font.h"
00036 #include "memory.h"
00037 #include "quickdraw.h"
00038 #include "strings.h"
00039 #include "ops.h"
00040 #include "resources.h"
00041 #include "shell.rsrc.h"
00042 #include "tablestructure.h"
00043 #include "timedate.h"
00044 #include "langinternal.h" /* 2006-02-26 creedon */
00045 #include "byteorder.h"  /* 2006-04-08 aradke: endianness conversion macros */
00046 
00047 
00048 #define ctparseparams 4
00049 
00050 #define hextoint(ch) (isdigit(ch)? (ch - '0') : (getlower (ch) - 'a' + 10))
00051     
00052 #define stringerrorlist 263
00053 
00054 /*
00055     constants related to text-conversion functions
00056 */
00057 #define cs_utf8         BIGSTRING( "\xA5" "utf-8" )
00058 #define cs_utf16        BIGSTRING( "\x06" "utf-16" )
00059 #define cs_iso88591     BIGSTRING( "\xA0" "iso-8859-1" )
00060 #define cs_macintosh    BIGSTRING( "\x09" "macintosh" )
00061 
00062 #ifdef WIN95VERSION
00063     #define kTextUnsupportedEncodingErr -8738
00064     #define kTextMalformedInputErr      -8739
00065     #define kTextUndefinedElementErr    -8740
00066     #define kTECNoConversionPathErr     -8749
00067     #define kTECPartialCharErr          -8753
00068 #endif
00069 
00070 byte zerostring [] = "\0"; /*use this to conserve constant space*/
00071 
00072 unsigned char lowercasetable[256];
00073 
00074 static hdlstring parseparams [ctparseparams] = {nil, nil, nil, nil};
00075 
00076 static hdlstring dirstrings [ctdirections];
00077 
00078 static byte bshexprefix [] = STR_hexprefix;
00079 
00080 
00081 /* declarations */
00082 
00083 static boolean converttextencoding( Handle, Handle, const long, const long, long * );
00084 static boolean getTextEncodingIDFromIANA( bigstring, long * );
00085 
00086 #ifdef WIN95VERSION
00087     static boolean UnicodeToAnsi(Handle, Handle, unsigned long, long *);
00088     static boolean AnsiToUnicode(Handle, Handle, unsigned long, long *);
00089 #endif
00090 
00091 
00092 /* definitions */
00093 
00094 boolean equalstrings (const bigstring bs1, const bigstring bs2) {
00095 
00096     /*
00097     return true if the two strings (pascal type, with length-byte) are
00098     equal.  return false otherwise.
00099     */
00100 
00101     register ptrbyte p1 = (ptrbyte) stringbaseaddress (bs1);
00102     register ptrbyte p2 = (ptrbyte) stringbaseaddress (bs2);
00103     register short ct = stringlength (bs1);
00104     
00105     if (ct != stringlength (bs2)) /*different lengths*/
00106         return (false);
00107     
00108     while (--ct >= 0) 
00109         
00110         if (*p1++ != *p2++)
00111         
00112             return (false);
00113         
00114     return (true); /*loop terminated*/
00115     } /*equalstrings*/
00116 
00117 
00118 boolean equaltextidentifiers (byte * string1, byte * string2, short len) {
00119     while (--len >= 0) 
00120         
00121         if (getlower (*string1++) != getlower (*string2++))
00122         
00123             return (false);
00124     
00125     return (true); /*loop terminated*/
00126     } /*equaltextidentifiers*/
00127 
00128 
00129 boolean equalidentifiers (const bigstring bs1, const bigstring bs2) {
00130     
00131     register long ct = stringlength (bs1);
00132     
00133     if (ct != stringlength (bs2)) /*different lengths*/
00134 
00135         return (false);
00136 
00137     else {
00138 
00139         register ptrbyte p1 = ((ptrbyte) bs1) + ct;
00140         register ptrbyte p2 = ((ptrbyte) bs2) + ct;
00141 
00142         while (--ct >= 0) 
00143 
00144             if (getlower (*p1--) != getlower (*p2--))
00145             
00146                 return (false);
00147         }
00148     
00149     return (true); /*loop terminated*/
00150     } /*equalidentifiers*/
00151 
00152 
00153 #ifdef THINK_C
00154 
00155 short comparestrings (bigstring bs1, bigstring bs2) {
00156 
00157     /*
00158     3/31/93 dmb: asm pascal string comparison, based on strncmp
00159     */
00160     
00161     asm {
00162             movem.l d3-d4,-(sp)     ;  save registers
00163             
00164             moveq   #0,d0           ;  D0.L = result
00165             movea.l bs1,a0          ;  A0 = bs1
00166             movea.l bs2,a1          ;  A1 = bs2
00167             
00168             moveq   #0,d1
00169             move.b  (a0)+,d1        ;  D1 = len1
00170             moveq   #0,d2
00171             move.b  (a1)+,d2        ;  D2 = len2
00172             
00173             move.l  d1,d3           ;  D3 = len1
00174             cmp.l   d2,d3
00175             ble.s   @1
00176             move.l  d2,d3           ;  D3 = min (len1, len2)
00177             
00178     @1      subq.l  #1,d3
00179     @2      bmi.s   @3
00180             move.b  (a0)+,d4
00181             cmp.b   (a1)+,d4
00182             beq.s   @1
00183             
00184             bra.s   @4
00185     @3      cmp.l   d2,d1
00186             beq.s   @9
00187             
00188     @4      bhi.s   @5
00189             subq.l  #2,d0
00190     @5      addq.l  #1,d0
00191     
00192     @9      movem.l (sp)+,d3-d4     ;  restore registers
00193         }
00194     } /*comparestrings*/
00195 
00196 #else
00197 
00198 short comparestrings (bigstring bs1, bigstring bs2) {
00199 
00200     /*
00201     3.0.2b1 dmb: use std c lib as much as possible
00202     */
00203     
00204     register short len1 = stringlength (bs1);
00205     register short len2 = stringlength (bs2);
00206     register short n;
00207     
00208     n = memcmp (stringbaseaddress (bs1), stringbaseaddress (bs2), min (len1, len2));
00209     
00210     if (n == 0)
00211         n = sgn (len1 - len2);
00212 
00213     /*
00214     AR 2004-08-24: memcmp is not guaranteed to return -1 || 0 || +1,
00215     but some of our callers expected -1 as the only negative value,
00216     make it so...
00217     */
00218     if (n < -1)
00219         return (-1);
00220     
00221     return (n);
00222     } /*comparestrings*/
00223 
00224 /*
00225 short comparestrings (bigstring bs1, bigstring bs2) {
00226 
00227     #*
00228     return zero if the two strings (pascal type, with length-byte) are
00229     equal.  return -1 if bs1 is less than bs2, or +1 if bs1 is greater than
00230     bs2.
00231     
00232     use the Machintosh international utility routine IUCompString, which 
00233     performs dictionary string comparison and accounts for accented characters
00234     %/
00235     
00236     return (IUCompString (bs1, bs2));
00237     } #*comparestrings*/
00238 
00239 #endif
00240 
00241 
00242 short compareidentifiers (bigstring bs1, bigstring bs2) {
00243 
00244     /*
00245     2004-11-09 aradke: cross between comparestrings and equalidentifiers,
00246     useful for sorting identifiers.
00247 
00248     return zero if the two strings (pascal type, with length-byte) are
00249     equal.  return -1 if bs1 is less than bs2, or +1 if bs1 is greater than
00250     bs2. the comparison is not case-sensitive.
00251     */
00252     
00253     register short n = min (stringlength (bs1), stringlength (bs2)) + 1;
00254     register ptrbyte p1 = (ptrbyte) stringbaseaddress (bs1);
00255     register ptrbyte p2 = (ptrbyte) stringbaseaddress (bs2);
00256     
00257     while (--n)
00258         if (getlower (*p1++) != getlower (*p2++))
00259             return ((getlower (*--p1) < getlower (*--p2)) ? -1 : +1); /*rewind*/
00260     
00261     return (sgn (stringlength (bs1) - stringlength (bs2)));
00262     } /*compareidentifiers*/
00263 
00264 
00265 boolean stringlessthan (register bigstring bs1, register bigstring bs2) {
00266     
00267     return (comparestrings (bs1, bs2) < 0);
00268     } /*stringlessthan*/
00269 
00270     
00271 boolean pushstring (bigstring bssource, bigstring bsdest) {
00272 
00273     /*
00274     insert the source string at the end of the destination string.
00275     
00276     assume the strings are pascal strings, with the length byte in
00277     the first character of the string.
00278     
00279     return false if the resulting string would be too long.
00280     */
00281     
00282     register short lensource = stringlength (bssource);
00283     register short lendest = stringlength (bsdest);
00284     register byte *psource, *pdest;
00285     
00286     if ((lensource + lendest) > lenbigstring) /*resulting string would be too long*/
00287         return (false);
00288         
00289     pdest = stringbaseaddress (bsdest) + lendest;
00290     
00291     psource = stringbaseaddress (bssource);
00292     
00293     setstringlength (bsdest, lendest + lensource);
00294     
00295 #ifdef SPEED
00296     moveleft (psource, pdest, lensource);
00297 #else
00298     while (lensource--) *pdest++ = *psource++;
00299 #endif  
00300     
00301     return (true);
00302     } /*pushstring*/
00303 
00304 
00305 boolean deletestring (bigstring bs, short ixdelete, short ctdelete) {
00306     
00307     /*
00308     delete ct chars in the indicated string, starting with the character
00309     at 1-based offset ix.
00310     */
00311     
00312     register short len = stringlength (bs);
00313     register long ctmove;
00314     register ptrbyte pfrom, pto;        
00315     
00316     if ((ixdelete > len) || (ixdelete < 1))
00317         return (false);
00318         
00319     if (ctdelete <= 0)
00320         return (ctdelete == 0);
00321         
00322     --ixdelete; // make zero-based
00323 
00324     ctmove = len - ixdelete - ctdelete;
00325      
00326     if (ctmove > 0) {
00327         
00328         pfrom = stringbaseaddress (bs) + ixdelete + ctdelete;
00329         
00330         pto = stringbaseaddress (bs) + ixdelete;
00331         
00332         moveleft (pfrom, pto, ctmove);
00333         }
00334     
00335     setstringlength (bs, len - ctdelete);
00336     
00337     return (true);
00338     } /*deletestring*/
00339 
00340 
00341 boolean deletefirstchar (bigstring bs) {    
00342     
00343     return (deletestring (bs, 1, 1));
00344     } /*deletefirstchar*/
00345     
00346     
00347 short popleadingchars (bigstring bs, byte ch) {
00348     
00349     /*
00350     2.1b1 dmb: return the number of characters popped
00351     */
00352     
00353     register short len = stringlength (bs);
00354     register short i;
00355     
00356     for (i = 0; i < len; i++) {
00357         
00358         if (getstringcharacter (bs, i) != ch) {
00359             
00360             deletestring (bs, 1, i);
00361             
00362             return (i);
00363             }
00364         } /*for*/
00365         
00366     setemptystring (bs);
00367     
00368     return (len);
00369     } /*popleadingchars*/
00370 
00371 
00372 short poptrailingchars (bigstring bs, byte ch) {
00373     
00374     /*
00375     5.1.3 dmb: pop the trailing characters, and return the new length
00376     */
00377     
00378     while (!isemptystring (bs) && (lastchar (bs) == ch))
00379         setstringlength (bs, stringlength (bs) - 1);
00380     
00381     return (stringlength (bs));
00382     } /*popleadingchars*/
00383 
00384 
00385 boolean pushchar (byte ch, bigstring bs) {
00386     
00387     /*
00388     insert the character at the end of a pascal string.
00389     */
00390     
00391     register short len;
00392     
00393     len = stringlength(bs); 
00394     
00395     if (len >= lenbigstring)
00396         return (false);
00397     
00398     setstringcharacter(bs, len, ch);
00399     
00400     setstringlength(bs, len+1);
00401     
00402     return (true);
00403     } /*pushchar*/
00404     
00405     
00406 boolean pushspace (bigstring bs) {
00407 
00408     /*
00409     an oft-repeated function, add a space at the end of bs.
00410     */
00411     
00412     return (pushchar (chspace, bs));
00413     } /*pushspace*/
00414     
00415     
00416 boolean pushlong (long num, bigstring bsdest) {
00417 
00418     bigstring bsint;
00419     
00420     numbertostring (num, bsint);
00421     
00422     return (pushstring (bsint, bsdest));
00423     } /*pushlong*/
00424     
00425 
00426 boolean pushint (short num, bigstring bsdest) {
00427     
00428     return (pushlong ((long) num, bsdest));
00429     } /*pushint*/
00430 
00431 /*
00432 pushboolean (boolean flboo, bigstring bsdest) {
00433     
00434     bigstring bsboo;
00435     
00436     if (flboo)
00437         copystring ((ptrstring) "\ptrue", bsboo);
00438     else
00439         copystring ((ptrstring) "\pfalse", bsboo);
00440         
00441     pushstring (bsboo, bsdest);
00442     } #*pushboolean*/
00443     
00444     
00445 /*
00446 pushstringresource (short listnum, short resnum, bigstring bs) {
00447     
00448     bigstring bsres;
00449     
00450     GetIndString (bsres, listnum, resnum);
00451     
00452     pushstring (bsres, bs);
00453     } #*pushstringresource*/
00454     
00455     
00456 boolean insertstring (bigstring bssource, bigstring bsdest) {
00457     
00458     /*
00459     insert the source string at the beginning of the destination string.
00460     
00461     return false if the resulting string would be longer than 255 chars.
00462     */
00463     
00464     register short len1 = stringlength (bssource), len2 = stringlength (bsdest);
00465     bigstring bs;
00466     
00467     if ((len1 + len2) > lenbigstring) /*resulting string would be too long*/
00468         return (false);
00469         
00470     copystring (bssource, bs);
00471     
00472     pushstring (bsdest, bs);
00473     
00474     copystring (bs, bsdest);
00475     
00476     return (true);
00477     } /*insertstring*/
00478 
00479 
00480 boolean insertchar (byte ch, bigstring bsdest) {
00481     
00482     register byte *pdest = bsdest;
00483     register short len = stringlength (pdest);
00484     
00485     if (len == lenbigstring)
00486         return (false);
00487     
00488     moveright (stringbaseaddress (pdest), stringbaseaddress (pdest) + 1, len);
00489     
00490     setstringlength (pdest, len + 1);
00491     
00492     setstringcharacter (pdest, 0, ch);
00493     
00494     return (true);
00495     } /*insertchar*/
00496 
00497 
00498 void midstring (bigstring bssource, short ix, short len, bigstring bsdest) {
00499     
00500     /*
00501     2.1b2 dmb: to make calling easier, protect again negative lengths
00502     */
00503     
00504     if (len <= 0)
00505         setemptystring (bsdest);
00506     
00507     else {
00508         
00509         setstringlength (bsdest, len);
00510         
00511         moveleft (stringbaseaddress (bssource) + ix - 1, stringbaseaddress (bsdest), (long) len);
00512         }
00513     } /*midstring*/
00514 
00515 
00516 boolean textfindreplace (Handle hfind, Handle hreplace, Handle hsearch, boolean flreplaceall, boolean flunicase) {
00517 
00518     /*
00519     dmb: this could be upgraded to use a handlestream
00520     
00521     6.1d4 AR: Updated to use a handlestream as per dmb's suggestion
00522 
00523     6.1d7 AR: Updated to handle unicase searching. Minor optimizations.
00524     */
00525     
00526     long ctfind, ctreplace;
00527     handlestream s;
00528     
00529     openhandlestream (hsearch, &s);
00530     
00531     lockhandle (hreplace);
00532     
00533     ctreplace = gethandlesize (hreplace);
00534     
00535     ctfind = gethandlesize (hfind);
00536     
00537     while (true) {
00538         
00539         s.pos = flunicase
00540             ? searchhandleunicase (hsearch, hfind, s.pos, s.eof)
00541             : searchhandle (hsearch, hfind, s.pos, s.eof);
00542 
00543         if (s.pos < 0) /*no match found*/
00544             break;
00545 
00546         if (!mergehandlestreamdata (&s, ctfind, *hreplace, ctreplace)) {
00547             
00548             closehandlestream (&s);
00549 
00550             unlockhandle (hreplace);
00551             
00552             return (false); //usually an out of memory error
00553             }
00554         
00555         if (!flreplaceall)
00556             break;
00557         }
00558     
00559     unlockhandle (hreplace);
00560     
00561     closehandlestream (&s);
00562 
00563     return (true);
00564     } /*textfindreplace*/
00565 
00566 
00567 boolean stringfindreplace (bigstring bsfind, bigstring bsreplace, Handle hsearch, boolean flreplaceall, boolean flunicase) {
00568 
00569     /*
00570     6.1b6 AR: Wrapper for textfindreplace. I got tired of replicating this functionality.
00571     */
00572 
00573     Handle hfind = nil;
00574     Handle hreplace = nil;
00575     boolean fl;
00576 
00577     fl = newtexthandle (bsfind, &hfind);
00578 
00579     fl = fl && newtexthandle (bsreplace, &hreplace);
00580 
00581     fl = fl && textfindreplace (hfind, hreplace, hsearch, flreplaceall, flunicase);
00582 
00583     disposehandle (hfind);
00584 
00585     disposehandle (hreplace);
00586 
00587     return (fl);
00588     }/*stringfindreplace*/
00589 
00590 
00591 boolean dropnonalphas (bigstring bs) {
00592 
00593 
00594     /*
00595     5.1.4 dmb: strip non alphas and return true if the string isn't empty
00596     */
00597     
00598     register short ct = stringlength (bs);
00599     
00600     while (--ct >= 0) {
00601         
00602         if (!isalnum (getstringcharacter (bs, ct)))
00603             deletestring (bs, ct + 1, 1);
00604         }
00605     
00606     return (!isemptystring (bs));
00607     } /*dropnonalphas*/
00608 
00609 
00610 boolean streamdropnonalphas (handlestream *s) {
00611 
00612 
00613     /*
00614     5.1.4 dmb: we needed this two places, to here it is
00615     */
00616     
00617     for ((*s).pos = 0; (*s).pos < (*s).eof; ) {
00618         
00619         if (isalnum ((*(*s).data) [(*s).pos]))
00620             ++(*s).pos;
00621         else
00622             pullfromhandlestream (s, 1, nil);
00623         }
00624     
00625     return (true);
00626     } /*streamdropnonalphas*/
00627 
00628 
00629 boolean scanstring (byte ch, bigstring bs, short *ix) {
00630     
00631     /*
00632     return in ix the index in the string of the first occurence
00633     of chscan.
00634     
00635     return false if it wasn't found, true otherwise.
00636     
00637     dmb 10/26/90: p is now initialized correctly to bs + i, not bs + 1
00638     
00639     dmb 1/22/97: using new string macros, be careful to preserve 1-basedness
00640     */
00641     
00642     register short i;
00643     register ptrbyte p;
00644     register byte c = ch;
00645     register short len = stringlength (bs);
00646     
00647     for (i = *ix - 1, p = stringbaseaddress (bs) + i; i < len; i++) 
00648         
00649         if (*p++ == c) {
00650             
00651             *ix = i + 1;
00652             
00653             return (true);
00654             }
00655             
00656     return (false);
00657     } /*scanstring*/
00658 
00659 
00660 boolean stringfindchar (byte ch, bigstring bs) {
00661     
00662     /*
00663     simpler entrypoint for scanstring when caller just wants 
00664     to know if ch appears anywhere in bs
00665     */
00666     
00667     short ix = 1;
00668     
00669     return (scanstring (ch, bs, &ix));
00670     } /*stringfindchar*/
00671 
00672 
00673 boolean stringreplaceall (char ch1, char ch2, bigstring bs) {
00674     
00675     /*
00676     replace all instances of ch1 in bs with ch2
00677     
00678     5.0d14 dmb: scanstring is 1-based, setstringcharacter is 0-based.
00679     */
00680     
00681     short ix = 1;
00682     
00683     while (scanstring (ch1, bs, &ix))
00684         setstringcharacter (bs, ix - 1, ch2);
00685     
00686     return (true);
00687     } /*stringreplaceall*/
00688 
00689 
00690 boolean textlastword (ptrbyte ptext, long len, byte chdelim, bigstring bsdest) {
00691     
00692     /*
00693     copy the last word from bs, and put it into bsdest.
00694     
00695     search backwards from the end of the source string until you find
00696     chdelim.
00697     */
00698     
00699     register long i;
00700     
00701     for (i = len; i > 0; i--) {
00702         
00703         if (ptext [i - 1] == chdelim)
00704             break;
00705         } /*for*/
00706     
00707     texttostring (ptext + i, len - i, bsdest);
00708     
00709     return (true);
00710     } /*textlastword*/
00711 
00712 
00713 boolean textfirstword (ptrbyte ptext, long len, byte chdelim, bigstring bsdest) {
00714     
00715     /*
00716     copy the first word from bs, and put it into bsdest.
00717     
00718     search forwards from the beginning of the source string until you 
00719     find chdelim.
00720     */
00721     
00722     register long i;
00723     
00724     for (i = 0; i < len; i++) {
00725         
00726         if (ptext [i] == chdelim)
00727             break;
00728         } /*for*/
00729     
00730     texttostring (ptext, i, bsdest);
00731     
00732     return (true);
00733     } /*textfirstword*/
00734 
00735 
00736 boolean textnthword (ptrbyte ptext, long len, long wordnum, byte chdelim, boolean flstrict, long *ixword, long *lenword) {
00737     
00738     /*
00739     6/10/91 dmb: a single word preceeded or followed by chdelim should be 
00740     counted as just one word
00741     
00742     8/7/92 dmb: added flstrict parameter. when set, every delimiter starts a new word, 
00743     even consecutive characters, possibly yielding empty words
00744     */
00745     
00746     register long ix;
00747     register long ixlastword;
00748     long ctwords = 1;
00749     boolean fllastwasdelim = true;
00750     
00751     ix = 0;
00752     
00753     ixlastword = 0;
00754     
00755     while (true) { /*scan string*/
00756         
00757         if (ix >= len) /*reached end of string*/
00758             break;
00759         
00760         if (ptext [ix] == chdelim) { /*at a delimiter*/
00761             
00762             if (ix == len - 1) /*trailing delimiter, don't bump word count*/
00763                 break;
00764             
00765             if (flstrict || !fllastwasdelim) {
00766                 
00767                 if (ctwords >= wordnum) /*we've found the end of the right word*/
00768                     break;
00769                 
00770                 ctwords++;
00771                 }
00772             
00773             ixlastword = ix + 1; /*next word starts after the delimiter*/
00774             
00775             fllastwasdelim = true;
00776             }
00777         else
00778             fllastwasdelim = false;
00779         
00780         ix++; /*advance to next character*/
00781         } /*while*/
00782     
00783     /*
00784     texttostring (ptext + ixlastword, ix - ixlastword, bsword);
00785     
00786     if (isemptystring (bsword) && !flstrict)
00787         return (false);
00788     */
00789     
00790     *ixword = ixlastword;
00791     
00792     *lenword = ix - ixlastword;
00793     
00794     if ((*lenword == 0) && !flstrict)
00795         return (false);
00796     
00797     return (ctwords == wordnum);
00798     } /*textnthword*/
00799 
00800 
00801 long textcountwords (ptrbyte ptext, long lentext, byte chdelim, boolean flstrict) {
00802     
00803     /*
00804     8/7/92 dmb: added flstrict parameter
00805     */
00806     
00807     register long wordnum = 1;
00808 //  bigstring bsword;
00809     long ixword;
00810     long lenword;
00811     
00812     while (true) {
00813         
00814         if (!textnthword (ptext, lentext, wordnum, chdelim, flstrict, &ixword, &lenword))
00815             return (wordnum - 1);
00816         
00817         wordnum++;
00818         } /*while*/
00819     } /*textcountwords*/
00820 
00821 
00822 boolean lastword (bigstring bssource, byte chdelim, bigstring bsdest) {
00823     
00824     return (textlastword (stringbaseaddress (bssource), stringlength (bssource), chdelim, bsdest));
00825     } /*lastword*/
00826     
00827 
00828 void poplastword (bigstring bs, byte chdelim) {
00829     
00830     bigstring bsword;
00831     
00832     if (lastword (bs, chdelim, bsword)) 
00833     
00834         setstringlength (bs, stringlength (bs) - stringlength (bsword));
00835     } /*poplastword*/
00836 
00837 
00838 boolean firstword (bigstring bssource, byte chdelim, bigstring bsdest) {
00839     
00840     return (textfirstword (stringbaseaddress (bssource), stringlength (bssource), chdelim, bsdest));
00841     } /*firstword*/
00842 
00843 
00844 boolean nthword (bigstring bs, short wordnum, byte chdelim, bigstring bsword) {
00845     
00846     long ixword;
00847     long lenword;
00848     
00849     if (!textnthword (stringbaseaddress (bs), stringlength (bs), wordnum, chdelim, false, &ixword, &lenword))
00850         return (false);
00851     
00852     texttostring (stringbaseaddress (bs) + ixword, lenword, bsword);
00853     
00854     return (true);
00855     } /*nthword*/
00856 
00857 
00858 boolean nthfield (bigstring bs, short fieldnum, byte chdelim, bigstring bsfield) {
00859     
00860     /*
00861     5.0.2b19 dmb: just like nthword, but flstrict
00862     */
00863     
00864     long ixfield;
00865     long lenfield;
00866     
00867     if (!textnthword (stringbaseaddress (bs), stringlength (bs), fieldnum, chdelim, true, &ixfield, &lenfield))
00868         return (false);
00869     
00870     texttostring (stringbaseaddress (bs) + ixfield, lenfield, bsfield);
00871     
00872     return (true);
00873     } /*nthfield*/
00874 
00875 
00876 short countwords (bigstring bs, byte chdelim) {
00877     
00878     return (textcountwords (stringbaseaddress (bs), stringlength (bs), chdelim, false));
00879     } /*countwords*/
00880 
00881 
00882 boolean textcommentdelete (Handle x) {
00883     
00884     /*
00885     5.0.2b15 dmb: moved guts out of commentdeleteverb. shorten the handle to 
00886     omit any comments -- ignoring URLs. (smarter than bigstring commentdelete.)
00887     */
00888     
00889     Handle hcomment;
00890     byte ch = chcomment;
00891     long ixcomment, ix2;
00892     
00893     //scan for doubleslash
00894     if (!newtexthandle (BIGSTRING ("\x02//"), &hcomment))
00895         return (false);
00896     
00897     ixcomment = searchhandle (x, hcomment, 0, longinfinity);
00898     
00899     while (ixcomment > 0) { //watch out for urls
00900         
00901         if ((*x) [ixcomment - 1] != ':')
00902             break;
00903         
00904         ixcomment = searchhandle (x, hcomment, ixcomment + 2, longinfinity);
00905         }
00906     
00907     //scan for Mac comment
00908     sethandlecontents (&ch, 1L, hcomment);
00909     
00910     if (ixcomment >= 0) {
00911     
00912         ix2 = searchhandle (x, hcomment, 0, ixcomment);
00913         
00914         if (ix2 >= 0)
00915             ixcomment = ix2;
00916         }
00917     else
00918         ixcomment = searchhandle (x, hcomment, 0, longinfinity);
00919     
00920     if (ixcomment >= 0)
00921         sethandlesize (x, ixcomment);
00922     
00923     disposehandle (hcomment);           //RAB: 1/27/98, clean up after one self
00924     
00925     return (true);
00926     } /*textcommentdelete*/
00927 
00928 
00929 long langcommentdelete (byte chdelim, byte *ptext, long ct) {
00930     
00931     /*
00932     scan the string from left to right.  if we find a comment delimiting
00933     character, return its offset
00934     
00935     10/30/91 dmb: ignore comment characters that are embedded in quoted strings
00936     
00937     5/4/93 dmb: handle single-quoted strings too
00938     
00939     3.0.2b1 dmb: handle escape sequences. note that we don't have to deal with 
00940     the 0x## form because ## can never be quote characters, and thus can't 
00941     confuse our string parsing
00942 
00943     5.0a12 dmb: handle // comments
00944     
00945     6.0a13 dmb: take ptext, ct instead of a big string, and return the comment
00946     offset instead of deleting anything. Note: textcommentdelete does _not_ 
00947     handle quoted strings.
00948     */
00949     
00950     register long i;
00951     register byte ch;
00952     boolean flinstring = false;
00953     boolean flinescapesequence = false;
00954     byte chendstring = 0;
00955     
00956     for (i = 0; i < ct; i++) {
00957         
00958         ch = ptext [i];
00959         
00960         if (flinstring) {
00961             
00962             if (flinescapesequence)
00963                 flinescapesequence = false; /*it's been consumed*/
00964             
00965             else {
00966                 
00967                 if (ch == (byte) '\\')
00968                     flinescapesequence = true;
00969                 else
00970                     flinstring = (ch != chendstring);
00971                 }
00972             }
00973         
00974         else if (ch == (byte) '"') {
00975             
00976             flinstring = true;
00977             
00978             chendstring = '"';
00979             }
00980         
00981         else if (ch == (byte) '') {
00982             
00983             flinstring = true;
00984             
00985             chendstring = '';
00986             }
00987         
00988         else if (ch == (byte) '\'') {
00989             
00990             flinstring = true;
00991             
00992             chendstring = '\'';
00993             }
00994         
00995         else if (ch == chdelim)
00996             return (i);
00997 
00998         else if (ch == '/') {
00999             
01000             if ((i + 1 < ct) && ptext [i+1] == '/')
01001                 return (i);
01002             }
01003         }
01004     
01005     return (-1);
01006     } /*langcommentdelete*/
01007 
01008 
01009 void commentdelete (byte chdelim, bigstring bs) {
01010     
01011     /*
01012     6.0a13 dmb: converted to use new langcommentdelete
01013     */
01014     
01015     long i;
01016     
01017     i = langcommentdelete (chdelim, stringbaseaddress (bs), stringlength (bs));
01018     
01019     if (i >= 0)
01020         setstringlength (bs, i);
01021     } /*commentdelete*/
01022 
01023 
01024 boolean whitespacechar (byte ch) {
01025     
01026     return ((ch == ' ') || (ch == '\t') || (ch == '\n') || (ch == '\r'));
01027     } /*whitespacechar*/
01028     
01029     
01030 boolean poptrailingwhitespace (bigstring bs) {
01031     
01032     /*
01033     return true if there were trailing "whitespace" characters to be popped.
01034     */
01035     
01036     register short i, ct;
01037     
01038     ct = stringlength (bs);
01039     
01040     for (i = ct; i > 0; i--)
01041     
01042         if (!whitespacechar (bs [i])) { /*found a non-blank character*/
01043             
01044             setstringlength (bs, i);
01045             
01046             return (i < ct);
01047             }
01048     
01049     setemptystring (bs);
01050     
01051     return (true); /*string is all blank*/
01052     } /*poptrailingwhitespace*/
01053     
01054     
01055 boolean firstsentence (bigstring bs) { 
01056     
01057     /*
01058     pops all characters after the first period followed by a space.
01059     
01060     return true if any chars were popped.
01061     */
01062     
01063     register short i;
01064     register short len = stringlength (bs);
01065     
01066     for (i = 0; i < len; i++) {
01067         
01068         if (getstringcharacter (bs, i) == '.') {
01069             
01070             if (i == len - 1) /*no next character, no chars to pop*/
01071                 return (false);
01072                 
01073             if (whitespacechar (getstringcharacter (bs, i+1))) { /*truncate length and return*/
01074                 
01075                 setstringlength (bs, i+1);
01076                 
01077                 return (true);
01078                 }
01079             }
01080         } /*for*/
01081         
01082     return (false); /*no chars popped*/
01083     } /*firstsentence*/
01084 
01085 /*  This is now initialized by initstrings and getlower is a macro in strings.h
01086 static boolean initlowercase = false;
01087 char lowercasetable[256];
01088 
01089 unsigned char getlower (unsigned char c) { /-fast lowercase functions-/
01090     int i;
01091 
01092     if (! initlowercase) {
01093         for (i = 0; i < 256; i++)
01094             lowercasetable[i] = tolower (i);
01095 
01096         initlowercase = true;
01097         }
01098 
01099     return (lowercasetable [c]);
01100     } /-getlower-/
01101 
01102 */
01103 
01104 void uppertext (ptrbyte ptext, long ctchars) {
01105     
01106     register ptrbyte p = ptext;
01107     register byte ch;
01108     
01109     while (--ctchars >= 0) {
01110         
01111         ch = *p;
01112         
01113         *p++ = toupper (ch);
01114         }
01115     } /*uppertext*/
01116 
01117 
01118 void lowertext (ptrbyte ptext, long ctchars) {
01119     
01120     register ptrbyte p = ptext;
01121     register byte ch;
01122     
01123     while (--ctchars >= 0) {
01124         
01125         ch = *p;
01126         
01127         *p++ = getlower (ch);
01128         }
01129     } /*lowertext*/
01130 
01131 
01132 void allupper (bigstring bs) {
01133     
01134     uppertext (stringbaseaddress (bs), stringlength (bs));
01135     } /*allupper*/
01136 
01137 
01138 void alllower (bigstring bs) {
01139     
01140     lowertext (stringbaseaddress (bs), stringlength (bs));
01141     } /*alllower*/
01142     
01143     
01144 boolean capitalizefirstchar (bigstring bs) {
01145     
01146     register char ch;
01147     
01148     if (stringlength (bs) == 0)
01149         return (true);
01150         
01151     ch = getstringcharacter (bs, 0);
01152     
01153     if (!islower (ch))
01154         return (false);
01155         
01156     setstringcharacter (bs, 0, toupper (ch));
01157     
01158     return (true);
01159     } /*capitalizefirstchar*/
01160     
01161     
01162 boolean isallnumeric (bigstring bs) {
01163     
01164     /*
01165     11/6/92 dmb: allow first character to be a sign instead of a digit
01166     */
01167     
01168     register short ct = stringlength (bs);
01169     register ptrbyte p = stringbaseaddress (bs);
01170     register byte ch;
01171     
01172     while (--ct >= 0) {
01173         
01174         ch = *p++;
01175         
01176         if (!isnumeric (ch)) {
01177             
01178             if (ct == stringlength (bs) - 1) { /*checking first character*/
01179                 
01180                 if ((ch == '-') || (ch == '+')) /*sign character -- it's cool*/
01181                     continue;
01182                 }
01183             
01184             return (false);
01185             }
01186         } /*while*/
01187         
01188     return (true); /*composed entirely of numeric chars*/
01189     } /*isallnumeric*/
01190     
01191     
01192 void filledstring (byte ch, short ct, bigstring bs) {
01193     
01194     /*
01195     1/17/97 dmb: recoded with string macros
01196     */
01197 
01198     if (ct < 0)
01199         ct = 0;
01200     
01201     setstringlength (bs, ct);
01202 
01203     memset (stringbaseaddress (bs), ch, (long) ct);
01204     /*
01205     bs [0] = ct;
01206 
01207     memset (&bs [1], ch, (long) ct);
01208     */
01209     } /*filledstring*/
01210 
01211 
01212 void padwithzeros (bigstring bs, short len) {
01213     
01214     /*
01215     2003-05-01 AR: insert zeros at beginning of string until
01216     we have reached the requested length;
01217     */
01218     
01219     if (len > lenbigstring)
01220         len = lenbigstring;
01221 
01222     while (len - stringlength (bs) > 0)
01223         insertchar ('0', bs);
01224 
01225     } /*padwithzeros*/
01226     
01227     
01228 void copystring (const bigstring bssource, bigstring bsdest) {
01229 
01230     /*
01231     create a copy of bssource in bsdest.  copy the length byte and
01232     all the characters in the source string.
01233 
01234     assume the strings are pascal strings, with the length byte in
01235     the first character of the string.
01236 
01237     1/17/97 dmb: recoded with string macros
01238     */
01239 
01240     register short len;
01241     
01242     if (bssource == nil) { /*special case, handled at lowest level*/
01243         
01244         setemptystring (bsdest);
01245         
01246         return;
01247         }
01248     
01249 #ifdef SPEED
01250     len = stringsize (bssource);
01251 
01252     moveleft ((ptrstring) bssource, bsdest, len);
01253 
01254 #else
01255     short i;
01256 
01257     len = stringlength (bssource);
01258 
01259     for (i = 0; i < len; i++)
01260         setstringcharacter (bsdest, i, getstringcharacter (bssource, i));
01261 
01262     setstringlength (bsdest, len);
01263 #endif
01264 
01265     /*
01266     len = (short) bssource [0];
01267     
01268     for (i = 0; i <= len; i++) 
01269         bsdest [i] = bssource [i];
01270     */
01271     } /*copystring*/
01272 
01273 
01274 void copyptocstring (const bigstring bssource, char *sdest) {
01275 
01276     short len = stringlength (bssource);
01277 
01278     memmove (sdest, stringbaseaddress (bssource), len);
01279 
01280     sdest [len] = '\0';
01281     } /*copyptocstring*/
01282 
01283 
01284 void copyctopstring (const char *ssource, bigstring bsdest) {
01285 
01286     short len = strlen (ssource);  /*YES: use strlen, this is a C string*/
01287 
01288     memmove (stringbaseaddress (bsdest), ssource, len);
01289 
01290     setstringlength (bsdest, len);
01291     } /*copyctopstring*/
01292 
01293 
01294 #ifdef WIN95VERSION
01295 
01296 void copyrezstring (const bigstring ssource, bigstring bsdest) {
01297 
01298     /*
01299     create a copy of bssource in bsdest.  copy the length byte and
01300     all the characters in the source string.
01301 
01302     3/10/97 rab:  The difference in this procedure is that the source is a C string
01303     */
01304 
01305     if (ssource == nil) { /*special case, handled at lowest level*/
01306         
01307         setemptystring (bsdest);
01308         
01309         return;
01310         }
01311     
01312     copyctopstring (ssource, bsdest);
01313     } /*copyrezstring*/
01314 
01315 #endif
01316 
01317 
01318 void copyheapstring (hdlstring hsource, bigstring bsdest) {
01319     
01320     /*
01321     a safe way of copying a string out of the heap into a stack-allocated or
01322     global string.
01323     */
01324     
01325     register hdlstring h = hsource;
01326     
01327     if (h == nil) { /*nil handles are empty strings*/
01328         
01329         setemptystring (bsdest);
01330         
01331         return;
01332         }
01333     
01334     // HLock ((Handle) h);
01335     
01336     copystring (*h, bsdest);
01337     
01338     // HUnlock ((Handle) h);
01339     } /*copyheapstring*/
01340     
01341     
01342 boolean pushheapstring (hdlstring hsource, bigstring bsdest) {
01343     
01344     register hdlstring h = hsource;
01345     register boolean fl;
01346     
01347     if (h == nil) /*nil handles are empty strings*/
01348         return (true);
01349         
01350     HLock ((Handle) h);
01351     
01352     fl = pushstring (*h, bsdest);
01353     
01354     HUnlock ((Handle) h);
01355     
01356     return (fl);
01357     } /*pushheapstring*/
01358 
01359 
01360 void timedatestring (long ptime, bigstring bs) {
01361     bigstring bstime;
01362 
01363     timetodatestring (ptime, bs, false);    
01364 
01365     getstringlist (interfacelistnumber, timedateseperatorstring, bstime);
01366 
01367     pushstring (bstime, bs);
01368 
01369     timetotimestring (ptime, bstime, true);
01370         
01371     pushstring (bstime, bs);
01372 
01373 #if 0
01374     /*
01375     12/12/91 dmb: include seconds so no information is lost
01376     */
01377     
01378     bigstring bstime;
01379     
01380     /*
01381     if (time == 0) {
01382         
01383         setemptystring (bs);
01384         
01385         return;
01386         }
01387     */
01388     
01389     IUDateString (ptime, shortDate, bs);
01390     
01391     getstringlist (interfacelistnumber, timedateseperatorstring, bstime);
01392     
01393     pushstring (bstime, bs);
01394     
01395     IUTimeString (ptime, true, bstime);
01396     
01397     pushstring (bstime, bs);
01398 #endif
01399     } /*timedatestring*/
01400 
01401 
01402 #ifdef MACVERSION
01403     static byte bsellipses [] = "\x01";
01404 #else
01405     static byte bsellipses [] = "\x03...";
01406 #endif
01407 
01408 void ellipsize (bigstring bs, short width) {
01409 
01410     /*
01411     if the string fits inside the given number of pixels, fine -- do nothing
01412     and return.
01413     
01414     if not, return a string that does fit, with ellipses representing the 
01415     deleted characters.  ellipses are generated by pressing option-semicolon.
01416 
01417     3/28/97 dmb: rewrote x-platform
01418 
01419     5.0.1 dmb: reenable Win code, but only for long strings to work around a 
01420     crashing bug I can't figure out.
01421 
01422     5.0.2 dmb: redisable Win code. We've reported thier User Breakpoint in DrawText
01423     bug, which we can't seem to workaround. I'm making our own code faster instead.
01424     */
01425     
01426     #ifdef xxxWIN95VERSION
01427         
01428         if (stringlength (bs) > 16) {
01429 
01430             RECT r;
01431             
01432             r.top = 0;
01433             r.bottom = 50;
01434             r.left = 0;
01435             r.right = width;
01436             
01437             pushemptyclip ();
01438             
01439             convertpstring (bs);
01440             
01441             setWindowsFont();
01442             
01443             DrawText (getcurrentDC(), bs, -1, &r, DT_END_ELLIPSIS | DT_MODIFYSTRING | DT_NOPREFIX);
01444             
01445             clearWindowsFont();
01446             
01447             convertcstring (bs);
01448             
01449             popclip ();
01450             }
01451     #endif
01452         {
01453         byte len;
01454         
01455         if (stringpixels (bs) <= width) //nothing to do, the string fits
01456             return;
01457         
01458         len = stringlength (bs); //current length in characters
01459         
01460         if (len < 2) //too short to truncate
01461             return;
01462         
01463         width -= stringpixels (bsellipses); //subtract width of ellipses
01464         
01465         //cut in half until it's shorter than available width
01466         do
01467             setstringlength (bs, len /= 2);
01468         while
01469             ((len > 1) && (stringpixels (bs) > width));
01470         
01471         //undo last halving, then go character by character
01472         setstringlength (bs, len *= 2);
01473 
01474         while (len > 1) {
01475             
01476             setstringlength (bs, --len);
01477 
01478             if (stringpixels (bs) <= width)
01479                 break;
01480             }
01481 
01482         pushstring (bsellipses, bs);
01483         }
01484     } /*ellipsize*/
01485 
01486 
01487 void parsedialogstring (const bigstring bssource, ptrstring bs0, ptrstring bs1, ptrstring bs2, ptrstring bs3, bigstring bsresult) {
01488         
01489     /*
01490     parse a string with up to four string parameters, following the syntax
01491     used by the Macintosh Dialog Manager in parsing strings.
01492     
01493     return the result of parsing bs in bsresult.
01494     
01495     where ^0 appears in text, push bs0 on the result string.
01496     
01497     may get fancier later, what if we allow you to imbed UserLand code?
01498     
01499     we work on a copy of the source string, so you may pass in the same string in
01500     bssource and bsresult.
01501     
01502     dmb 10/8/90: accept nil parameters
01503     */
01504     
01505     bigstring bs;
01506     register short len;
01507     register short i;
01508     register byte ch;
01509     ptrstring params [ctparseparams];
01510     register short paramnum;
01511     
01512     copystring (bssource, bs); /*work on a copy of the source string*/
01513     
01514     len = stringlength (bs); /*copy into register*/
01515     
01516     params [0] = bs0;
01517     
01518     params [1] = bs1;
01519     
01520     params [2] = bs2;
01521     
01522     params [3] = bs3;
01523     
01524     setemptystring (bsresult);
01525     
01526     for (i = 1; i <= len; i++) {
01527         
01528         ch = bs [i];
01529         
01530         if (ch != '^')
01531             pushchar (ch, bsresult);
01532             
01533         else {
01534             if (i == len) /*the ^ is at the end of the string, no number*/
01535                 return;
01536             
01537             paramnum = bs [i + 1] - '0'; /*index into params array*/
01538             
01539             if ((paramnum >= 0) && (paramnum <= 3)) {
01540                 
01541                 assert (params [paramnum] != nil); /*string should always be provided*/
01542                 
01543                 pushstring (params [paramnum], bsresult);
01544                 
01545                 i++; /*advance over numeric character*/
01546                 }
01547             else
01548                 pushchar ('^', bsresult); 
01549             }
01550         } /*for*/
01551     
01552     /***subtractstrings (bsresult, "\p ", bsresult); #*in case there was a missing param*/
01553     } /*parsedialogstring*/
01554 
01555 boolean parsedialoghandle (Handle hsource, Handle h0, Handle h1, Handle h2, Handle h3) {
01556         
01557     /*
01558     6.1d1 AR: parse a handle with up to four handle parameters, following the syntax
01559     used by the Macintosh Dialog Manager in parsing strings.
01560     
01561     we work on the source handle.
01562     
01563     where ^0 appears in text, insert h0 into the source handle, etc.
01564     */
01565     
01566     register long i, sizediff;
01567     register long maxi = gethandlesize (hsource) - 1; /*we only need to loop till the 2nd to last char*/
01568     Handle params [ctparseparams];
01569     register short paramnum;
01570     
01571     params [0] = h0;
01572     
01573     params [1] = h1;
01574     
01575     params [2] = h2;
01576     
01577     params [3] = h3;
01578     
01579     for (i = 0; i < maxi; i++) {
01580                 
01581         if ((*hsource) [i] != '^') /*look for carets only*/
01582             continue;
01583 
01584         paramnum = (*hsource) [i + 1] - '0'; /*index into params array*/
01585         
01586         if ((paramnum < 0) || (paramnum > 3)) /*check range*/
01587             continue;
01588         
01589         assert (params [paramnum] != nil); /*handle should always be provided*/
01590         
01591         if (!pullfromhandle (hsource, i, 2, nil))
01592             return (false);
01593         
01594         if (!inserthandleinhandle (params [paramnum], hsource, i))
01595             return (false);
01596         
01597         sizediff = gethandlesize (params [paramnum]) - 2; /*advance over inserted characters*/
01598 
01599         i += sizediff;
01600 
01601         maxi += sizediff;
01602 
01603         } /*for*/
01604     
01605     return (true);
01606     
01607     } /*parsedialogstring*/
01608 
01609 
01610 boolean setparseparams (bigstring bs0, bigstring bs1, bigstring bs2, bigstring bs3) {
01611     
01612     /*
01613     dmb 10/8/90: accept nil parameters
01614     */
01615     
01616     register short i;
01617     
01618     for (i = 0; i < ctparseparams; i++) {
01619     
01620         disposehandle ((Handle) parseparams [i]);
01621         
01622         parseparams [i] = nil;
01623         } /*for*/
01624     
01625     if (bs0 != nil)
01626         if (!newheapstring (bs0, &parseparams [0]))
01627             return (false);
01628     
01629     if (bs1 != nil)
01630         if (!newheapstring (bs1, &parseparams [1]))
01631             return (false);
01632     
01633     if (bs2 != nil)
01634         if (!newheapstring (bs2, &parseparams [2]))
01635             return (false);
01636     
01637     if (bs3 != nil)
01638         if (!newheapstring (bs3, &parseparams [3]))
01639             return (false);
01640     
01641     return (true);
01642     } /*setparseparams*/
01643     
01644     
01645 void parseparamstring (bigstring bsparse) {
01646     
01647     bigstring bs [ctparseparams];
01648     register short i;
01649     register hdlstring hstring;
01650     
01651     for (i = 0; i < ctparseparams; i++) {
01652         
01653         hstring = parseparams [i];
01654         
01655         if (hstring == nil)
01656             setemptystring (bs [i]);
01657         else
01658             copyheapstring (hstring, bs [i]);
01659         } /*for*/
01660     
01661     parsedialogstring (bsparse, bs [0], bs [1], bs [2], bs [3], bsparse);
01662     } /*parseparamstring*/
01663 
01664 
01665 void getstringresource (short resnum, bigstring bs) {
01666 #ifdef MACVERSION   
01667     /*
01668     get a string resource, numbered resnum.  if there's an error,
01669     set the string to the empty string.
01670     */
01671     
01672     StringHandle hstring;
01673     
01674     hstring = GetString (resnum);
01675     
01676     if (hstring == nil)
01677         setemptystring (bs);
01678     else
01679         copyheapstring (hstring, bs);
01680 #endif
01681     } /*getstringresource*/
01682 
01683 
01684 void parsenumberstring (short listnum, short id, long number, bigstring bsparse) {
01685     
01686     /*
01687     if number is one, use id; otherwise, use id + 1.  then parse the number in
01688     */
01689     
01690     bigstring bsnumber;
01691     
01692     numbertostring (number, bsnumber);
01693     
01694     if (number != 1)
01695         ++id;
01696     
01697     getstringlist (listnum, id, bsparse);
01698     
01699     parsedialogstring (bsparse, bsnumber, nil, nil, nil, bsparse);
01700     } /*parsenumberstring*/
01701 
01702 
01703 
01704 #ifdef WIN95VERSION
01705 boolean copyWideToPString( const wchar_t * inString, bigstring bs )
01706 {
01707     DWORD err;
01708     size_t lenOut;
01709 
01710     lenOut = WideCharToMultiByte( 1252, 0,(wchar_t *) inString, -1, bs,
01711                   255, NULL, NULL);
01712     
01713     if ( lenOut == 0 )
01714     {
01715         err = GetLastError();
01716         
01717         switch ( err )
01718         {
01719             case ERROR_INSUFFICIENT_BUFFER: /* these are the err codes it can return */
01720             case ERROR_INVALID_FLAGS:       /* I'm just not yet sure how to handle them */
01721             case ERROR_INVALID_PARAMETER:
01722                 return ( false );
01723             
01724             case S_OK:
01725                 break;
01726         }
01727     }
01728     
01729     convertcstring( bs );
01730 
01731     return (true);
01732 } /* copyWideToPString */
01733 
01734 boolean copyPStringToWide( bigstring bs, long * lenResult, wchar_t * outString )
01735 {
01736     HRESULT err;
01737     size_t lenIn;
01738     bigstring bsCString;
01739 
01740     lenIn = (size_t) bs[ 0 ];
01741 
01742     copystring( bs, bsCString );
01743     convertpstring( bsCString );
01744     
01745     *lenResult = (long) MultiByteToWideChar( 1252, 0, bsCString, lenIn, (LPWSTR) outString, 255 );
01746     
01747     if ( *lenResult == 0 )
01748     {
01749         err = GetLastError();
01750         
01751         switch ( err )
01752         {
01753             case ERROR_INSUFFICIENT_BUFFER: /* these are the err codes it can return */
01754             case ERROR_INVALID_FLAGS:       /* I'm just not yet sure how to handle them */
01755             case ERROR_INVALID_PARAMETER:
01756                 return ( false );
01757             
01758             case S_OK:
01759                 break;
01760         }
01761     }
01762 
01763     outString[ *lenResult ] = L'\0'; /* the API doesn't seem to do this consistently */
01764 
01765     return ( true );
01766 }
01767 #endif
01768 
01769 void convertpstring (bigstring bs) {
01770     
01771     /*
01772     convert a pascal string to a c string.
01773     */
01774     
01775     register short len;
01776     
01777     len = (short) bs [0];
01778     
01779     moveleft (&bs [1], &bs [0], (long) len);
01780     
01781     bs [len] = 0; /*dmb 8/1/90:  shouldn't add 1 to len here*/
01782     } /*convertpstring*/
01783     
01784     
01785 void convertcstring (bigstring bs) {
01786     
01787     /*
01788     convert a c string to a pascal string.
01789     */
01790     
01791     register ptrbyte p;
01792     register short len = 0;
01793     
01794     p = &bs [0]; /*point at the first byte in c string*/
01795     
01796     while (*p++) len++;
01797     
01798     moveright (&bs [0], &bs [1], (long) len);
01799     
01800     bs [0] = (byte) len;
01801     } /*convertcstring*/
01802 
01803 
01804 long textpatternmatch (byte *ptext, long lentext, bigstring bsfind, boolean flunicase) {
01805     
01806     /*
01807     return the offset into ptext of the match, or -1.
01808     
01809     this uses an algorithm attributed to Boyer-Moore, I believe.  it uses 
01810     cryptic macros above to support case-insensitivity with maximum performance.
01811     
01812     2006-04-02 aradke: The search failed when the pattern was longer than 129 chars
01813         because the jump table for the Boyer-Moore algorithm was defined as an array
01814         of signed chars, causing an overflow for jump distances larger than 129 chars.
01815         The fix is to define the jump table as an array of signed longs instead. [bug #1463056]
01816         http://sourceforge.net/tracker/index.php?func=detail&aid=1463056&group_id=120666&atid=687798
01817     */
01818     
01819     register byte *p = ptext;
01820     byte *pend = p + lentext;
01821     byte *psave;
01822     long i;
01823     long dist;
01824     long lenpattern;
01825     long jump [256];
01826     boolean flcase = !flunicase;
01827     ptrstring bspattern = bsfind;
01828     #define checklower(c) (flcase? (c) : getlower (c))
01829     
01830     lenpattern = stringlength (bspattern);
01831     
01832     /*fill in the jump array according to the characters in the search pattern*/
01833     
01834     for (i = 0;  i <= 255;  i++)
01835         jump [i] = lenpattern;
01836     
01837     for (i = 1;  i <= lenpattern;  i++)
01838         jump [bspattern [i]] = 1 - i;
01839     
01840     /*start the search*/
01841     
01842     p += lenpattern - 1;
01843     
01844     while (p < pend) {
01845         
01846         dist = jump [checklower (*p)];
01847         
01848         p += dist;
01849         
01850         if (dist <= 0) { /*p was a member of the target pattern*/
01851             
01852             psave = p; /*p is now @potential beginning of string*/
01853             
01854             if (p + lenpattern > pend) /*not enough room for a match*/
01855                 return (-1);
01856             
01857             i = 1;
01858             
01859             while (checklower (*p++) == bspattern [i++]) {
01860                 
01861                 if (i > lenpattern)
01862                     return (psave - ptext);
01863                 }
01864             
01865             /*fell through; reset search to position following last check*/
01866             
01867             p = psave - dist + 1;
01868             }
01869         }
01870     
01871     return (-1);
01872     } /*textpatternmatch*/
01873 
01874 
01875 short patternmatch (bigstring bspattern, bigstring bs) {
01876     
01877     /*
01878     the beginning of something bigger.  first version -- search for the 
01879     pattern in the string, return the offset of the first occurrence of
01880     the pattern.  0 if not found.
01881     */
01882     
01883     register short lenstring = stringlength (bs);
01884     register short lenpattern = stringlength (bspattern);
01885     register short ixstring = 0;
01886     register byte chfirst;
01887     register short i, ix;
01888     
01889     if ((lenstring == 0) || (lenpattern == 0))
01890         return (0);
01891     
01892     chfirst = getstringcharacter (bspattern, 0);
01893     
01894     while (true) {
01895         
01896         if (getstringcharacter (bs, ixstring) == chfirst) { /*matched at least first character in string*/
01897             
01898             for (i = 1; i < lenpattern; i++) {
01899                 
01900                 ix = ixstring + i;
01901                 
01902                 if (ix >= lenstring) /*gone off end of string, can't match*/
01903                     return (0);
01904                 
01905                 if (getstringcharacter (bs, ix) != getstringcharacter (bspattern, i)) 
01906                     goto L1;
01907                 } /*for*/
01908             
01909             return (ixstring + 1); /*loop terminated, full match*/
01910             }
01911         
01912         L1: /*advance to next character in string*/
01913         
01914         if (++ixstring > lenstring) /*reached end of string, not found*/
01915             return (0);
01916         } /*while*/
01917     } /*patternmatch*/
01918 
01919 
01920 boolean addstrings (bigstring bs1, bigstring bs2, bigstring bsdest) {
01921     
01922     /*
01923     return the result of concatenating the first string and the second 
01924     string.
01925     
01926     return false if the result is too long
01927     */
01928     
01929     copystring (bs1, bsdest);
01930     
01931     return (pushstring (bs2, bsdest));
01932     } /*addstrings*/
01933 
01934 
01935 boolean subtractstrings (bigstring bs1, bigstring bs2, bigstring bsdest) {
01936     
01937     /*
01938     given the first two strings, return a string that's the result of deleting 
01939     the first instance of the second string from the first string.
01940     
01941     return false if the second string doesn't appear in the first.
01942     */
01943     
01944     register short ix;
01945     
01946     copystring (bs1, bsdest); /*default: return first string unchanged*/
01947     
01948     ix = patternmatch (bs2, bs1);
01949     
01950     if (ix > 0) { /*found it*/
01951         
01952         deletestring (bsdest, ix, stringlength (bs2));
01953         
01954         return (true);
01955         }
01956     
01957     return (false); /*didn't change string*/
01958     } /*subtractstrings*/
01959     
01960 
01961 void ostypetostring (OSType type, bigstring bs) {
01962     
01963     setstringlength (bs, sizeof (OSType));
01964     
01965     disktomemlong (type);
01966 
01967     moveleft (&type, stringbaseaddress (bs), longsizeof (OSType));
01968 
01969     //RAB: 1/22/98 removed this from here and added it in filedialog.c
01970     //#ifdef WIN95VERSION
01971     //  poptrailingwhitespace (bs);
01972     //#endif
01973     } /*ostypetostring*/
01974     
01975     
01976 boolean stringtoostype (bigstring bs, OSType *type) {
01977     
01978     /*
01979     2.1b4 dmb: always copy into type, even when returning false for bad length
01980     */
01981 
01982     // kw 2005-11-28 changed to unsigned for better match with stringlength()
01983     register unsigned short len = stringlength (bs);
01984     boolean fl = true;
01985     
01986     *type = '    ';
01987     
01988     if (len > sizeof (OSType)) {
01989         
01990         len = sizeof (OSType);
01991         
01992         fl = false;
01993         }
01994         
01995     moveleft (stringbaseaddress (bs), type, (long) len);
01996     
01997     disktomemlong (*type);
01998     
01999     return (fl);
02000     } /*stringtoostype*/
02001 
02002 
02003 boolean hexstringtonumber (bigstring bshex, long *n) {
02004     
02005     register long x = 0;
02006     register char ch;
02007     register short i;
02008     register short len;
02009     bigstring bs;
02010     boolean fl = true;
02011     boolean flsignextend;
02012     
02013     copystring (bshex, bs);
02014     
02015     stringdeletechars (bs, chspace);
02016     
02017     subtractstrings (bs, bshexprefix, bs);
02018     
02019     flsignextend = stringlength (bs) == 4;
02020     
02021     popleadingchars (bs, '0');
02022     
02023     alllower (bs);
02024     
02025     len = min (stringlength (bs), 8);
02026     
02027     for (i = 1; i <= len; ++i) {
02028         
02029         x <<= 4; /*one nibble per character*/
02030         
02031         ch = getstringcharacter (bs, i - 1);
02032         
02033         if (isxdigit (ch))
02034             x += hextoint (ch);
02035         
02036         else {
02037             fl = false;
02038             
02039             break;
02040             }
02041         }
02042     
02043     if (flsignextend) { /*need so sign-extend as an integer*/
02044         
02045         i = x;
02046         
02047         x = i;
02048         }
02049     
02050     *n = x;
02051     
02052     return (fl);
02053     } /*hexstringtonumber*/
02054 
02055 
02056 void bytestohexstring (ptrvoid pdata, long ctbytes, bigstring bshex) {
02057     
02058     register byte *p = pdata;
02059     register byte x;
02060     register long ct = ctbytes;
02061     byte bsbyte [3];
02062     static byte hex [16] = "0123456789ABCDEF";
02063     
02064     setemptystring (bshex);
02065     
02066     setstringlength (bsbyte, 2);
02067     
02068     ct = min (ctbytes, lenbigstring / 2 - 2); /*leave room for hex prefix*/
02069     
02070     while (--ct >= 0) {
02071         
02072         x = *p++;
02073         
02074         bsbyte [1] = hex [(x >> 4) & 0x000F];
02075         
02076         bsbyte [2] = hex [x & 0x000F];
02077         
02078         pushstring (bsbyte, bshex);
02079         }
02080     
02081     insertstring (bshexprefix, bshex);
02082     } /*bytestohexstring*/
02083 
02084 
02085 void numbertohexstring (long number, bigstring bshex) {
02086     
02087     /*
02088     5.0a21 dmb: set byte order to little-endian (Motorola)
02089     */
02090 
02091     if ((number < -32768) || (number > 32767))  {
02092         
02093         memtodisklong (number);
02094 
02095         bytestohexstring (&number, sizeof (long), bshex);
02096         }
02097     
02098     else {
02099         
02100         short x = number;
02101         
02102         memtodiskshort (x);
02103 
02104         bytestohexstring (&x, sizeof (short), bshex);
02105         }
02106     } /*numbertohexstring*/
02107 
02108 
02109 boolean bytestohex (Handle hbytes, Handle *hhex) {
02110     
02111     register byte *pbytes;
02112     register byte *phex;
02113     register long ct;
02114     byte x;
02115     static byte hex [16] = "0123456789ABCDEF";
02116     
02117     ct = gethandlesize (hbytes);
02118     
02119     if (!newhandle (stringlength (bshexprefix) + ct * 2, hhex))
02120         return (false);
02121     
02122     pbytes = (byte *) *hbytes; /*it's not going to move now that we've allocated return handle*/
02123     
02124     phex = (byte *) **hhex;
02125     
02126     moveleft (stringbaseaddress (bshexprefix), phex, stringlength (bshexprefix));
02127     
02128     phex += stringlength (bshexprefix);
02129     
02130     while (--ct >= 0) {
02131         
02132         x = *pbytes++;
02133         
02134         *phex++ = hex [(x >> 4) & 0x000F];
02135         
02136         *phex++ = hex [x & 0x000F];
02137         }
02138     
02139     return (true);
02140     } /*bytestohex*/
02141 
02142 
02143 boolean hextobytes (Handle hhex, Handle *hbytes) {
02144     
02145     /*
02146     5.0a2 dmb: ct must be long, not short
02147     */
02148     
02149     register byte *pbytes;
02150     register byte *phex;
02151     register long ct;
02152     long x;
02153     char ch;
02154     boolean flhashexprefix;
02155     
02156     ct = gethandlesize (hhex);
02157     
02158     phex = (byte *) *hhex;
02159     
02160     flhashexprefix = (phex [1] == 'x');
02161     
02162     if (flhashexprefix)
02163         ct -= 2;
02164     
02165     ct /= 2; /*one byte per two hex characters*/
02166     
02167     if (!newhandle (ct, hbytes))
02168         return (false);
02169     
02170     pbytes = (byte *) **hbytes; /*it's not going to move now that we've allocated return handle*/
02171     
02172     phex = (byte *) *hhex;
02173     
02174     if (flhashexprefix)
02175         phex += 2;
02176     
02177     while (--ct >= 0) {
02178         
02179         ch = *phex++; /*get high nibble first*/
02180         
02181         x = hextoint (ch) << 4;
02182         
02183         ch = *phex++; /*get low nibble*/
02184         
02185         x |= hextoint (ch);
02186         
02187         *pbytes++ = x;
02188         }
02189     
02190     return (true);
02191     } /*bytestohexstring*/
02192 
02193 
02194 void kstring (long ctbytes, bigstring bs) {
02195     
02196     bigstring bskilo;
02197     
02198     numbertostring (ctbytes / 1024, bs);
02199     
02200     getstringlist (interfacelistnumber, kilobytestring, bskilo);
02201     
02202     pushstring (bskilo, bs);
02203     } /*kstring*/
02204 
02205 
02206 void dirtostring (tydirection dir, bigstring bs) {
02207     
02208     register short ix;
02209     
02210     ix = dirtoindex (dir);
02211     
02212     if (ix < 0)
02213         ix = 0; /*index for nodirection*/
02214     
02215     copyheapstring (dirstrings [ix], bs);
02216     } /*dirtostring*/
02217 
02218 
02219 boolean stringtodir (bigstring bs, tydirection *dir) {
02220     
02221     register short i;
02222     
02223     alllower (bs); /*matching is unicase*/
02224     
02225     for (i = 0; i < ctdirections; i++) {
02226         
02227         bigstring bsdirection;
02228         
02229         copyheapstring (dirstrings [i], bsdirection);
02230         
02231         alllower (bsdirection);
02232         
02233         if (equalstrings (bs, bsdirection)) {
02234             
02235             *dir = indextodir (i);
02236             
02237             return (true);
02238             }
02239         } /*for*/
02240     
02241     *dir = nodirection;
02242     
02243     return (false);
02244     } /*stringtodir*/
02245     
02246 
02247 boolean midinsertstring (bigstring bsinsert, bigstring bs, short ixinsert) {
02248     
02249     /*
02250     insert bsinsert in the indicated string at offset ixinsert.
02251     */
02252     
02253     short ix = ixinsert - 1; // make zero-based
02254     short leninsert = stringlength (bsinsert);
02255     short origlen = stringlength (bs);
02256     short newlen = leninsert + origlen;
02257     ptrbyte pinsert = stringbaseaddress (bs) + ix;
02258     
02259     if (newlen > lenbigstring)
02260         return (false);
02261     
02262     moveright (pinsert, pinsert + leninsert, (long) origlen - ix);
02263     
02264     moveleft (stringbaseaddress (bsinsert), pinsert, (long) leninsert);
02265     
02266     setstringlength (bs, newlen);
02267     
02268     return (true);
02269     } /*midinsertstring*/
02270 
02271 
02272 boolean replacestring (bigstring bsreplace, short ix, short ctreplace, bigstring bsinsert) {
02273     
02274     /*
02275     4/3/92 dmb: check for overflow before doing deletion
02276     */
02277     
02278     if (stringlength (bsreplace) + (stringlength (bsinsert) - ctreplace) > lenbigstring)
02279         return  (false);
02280     
02281     deletestring (bsreplace, ix, ctreplace);
02282     
02283     midinsertstring (bsinsert, bsreplace, ix);
02284     
02285     return (true);
02286     } /*replacestring*/
02287 
02288 
02289 boolean stringaddcommas (bigstring bs) {
02290     
02291     /*
02292     turn a string like "98760241" into "98,760,241".
02293     
02294     5.0a24 dmb: bug don't turn "760241" into ",760,241"
02295     */
02296     
02297     register short ix = stringlength (bs); /*start at the end of the string*/
02298     bigstring bscomma;
02299     
02300     getstringlist (interfacelistnumber, commastring, bscomma);
02301     
02302     while (true) {
02303         
02304         ix -= 3;
02305         
02306         if (ix <= 0) /*ran out of characters*/
02307             return (true);
02308         
02309         if (getstringcharacter (bs, ix) == '-') /*no comma between a minus and the number*/
02310             return (true);
02311         
02312         midinsertstring (bscomma, bs, ix + 1);
02313         } /*while*/
02314     } /*stringaddcommas*/
02315     
02316     
02317 boolean stringdeletechars (bigstring bs, char ch) {
02318     
02319     /*
02320     delete all occurrences of the char in the string.
02321     
02322     return true if we actually deleted a character.
02323     */
02324     
02325     register short i;
02326     register short len;
02327     register boolean fl = false;
02328     
02329     len = stringlength (bs);
02330     
02331     for (i = 1; i <= len; i++) {
02332         
02333         if (getstringcharacter (bs, i - 1) == ch) {
02334             
02335             deletestring (bs, i, 1);
02336             
02337             i--; /*look at the same position again*/
02338             
02339             len--; /*one fewer chars to look at*/
02340             
02341             fl = true;
02342             }
02343         } /*for*/
02344     
02345     return (fl);
02346     } /*stringdeletechars*/
02347             
02348 
02349 boolean assurelastchariscolon (bigstring bs) {
02350 
02351     if (lastchar (bs) == ':')
02352         return (true);
02353         
02354     return (pushchar (':', bs));
02355     } /*assurelastchariscolon*/
02356 
02357 
02358 
02359 static short getTextEncodingErrorNumFromOSCode( long osStatusCode )
02360 {
02361     switch ( osStatusCode )
02362     {
02363         case kTextUnsupportedEncodingErr:
02364             return 3;
02365         case kTextMalformedInputErr:
02366             return 4;
02367         case kTextUndefinedElementErr:
02368             return 5;
02369         case kTECNoConversionPathErr:
02370             return 6;
02371         case kTECPartialCharErr:
02372             return 7;
02373         
02374         default:
02375             return 2;
02376     }
02377 }
02378 
02379 static void setTextEncodingConversionError( const bigstring encIn, const bigstring encOut, long osStatusCode )
02380 {
02381     short errStringNum = getTextEncodingErrorNumFromOSCode( osStatusCode );
02382     bigstring rezErrorMessage, bsErrorMessage;
02383     
02384     if ( ! getstringlist( stringerrorlist, errStringNum, rezErrorMessage ) )
02385         getstringlist( stringerrorlist, 1, rezErrorMessage );
02386     
02387     parsedialogstring( rezErrorMessage, (ptrstring) encIn, (ptrstring) encOut, nil, nil, bsErrorMessage );
02388     
02389     langerrormessage( bsErrorMessage );
02390 }
02391 
02392 
02393 #ifdef WIN95VERSION
02394 
02395 static boolean UnicodeToAnsi( Handle h, Handle hresult, unsigned long encoding, long * errCode )
02396 {
02397     /*
02398     7.0b42 PBS: convert from Unicode to Ansi. Borrowed from Microsoft sample code.
02399     */
02400 
02401     ULONG cbAnsi, cCharacters;
02402     long lentext;
02403     
02404     cCharacters = wcslen((wchar_t *) *h)+1;
02405  
02406     cbAnsi = cCharacters * 2;
02407 
02408     sethandlesize (hresult, cbAnsi);
02409 
02410     // Convert to ANSI.
02411     lentext = WideCharToMultiByte( encoding, 0, (wchar_t *) *h, -1, *hresult, cbAnsi, NULL, NULL);
02412     
02413     if ( lentext == 0 )  // report error
02414     {
02415         * errCode = GetLastError();
02416         
02417         return ( false );
02418     }
02419     
02420     *errCode = S_OK;
02421     
02422     sethandlesize (hresult, lentext - 1);
02423     
02424     return ( true );
02425     }
02426 
02427 
02428 static boolean AnsiToUnicode( Handle h, Handle hresult, unsigned long encoding, long * errCode )
02429 {
02430     /*
02431     7.0b42 PBS: convert from ANSI to Unicode. Borrowed from Microsoft sample code.
02432     */
02433 
02434     ULONG cbUni, cCharacters;
02435     long lentext;
02436 
02437     cCharacters = gethandlesize (h);
02438 
02439     // Determine number of bytes to be allocated for ANSI string. An
02440     // ANSI string can have at most 2 bytes per character (for Double
02441     // Byte Character Strings.)
02442     cbUni = cCharacters * 4;
02443 
02444     sethandlesize (hresult, cbUni);
02445 
02446     // Convert to ANSI.
02447     lentext = MultiByteToWideChar (encoding, 0, *h, cCharacters, (wchar_t *) *hresult, cbUni);
02448     
02449     if ( lentext == 0 )
02450     {
02451         * errCode = GetLastError();
02452         
02453         return ( false );
02454     }
02455     
02456     * errCode = S_OK;
02457     
02458     sethandlesize( hresult, ( lentext + 1 ) * 2 );
02459     ((wchar_t *)(*hresult))[lentext] = L'\0';
02460 
02461     return ( true );
02462 } 
02463 
02464 #endif /*end Windows character conversion routines*/
02465 
02466 
02467 /* convert an "internet name" for an encoding into a platform-specific id for the character set */
02468 
02469 static boolean getTextEncodingIDFromIANA( bigstring bsEncodingName, long * encodingId )
02470 {
02471     #ifdef MACVERSION
02472 
02473         OSStatus err;
02474         TextEncoding oneEncoding;
02475         
02476         err = TECGetTextEncodingFromInternetName( &oneEncoding, bsEncodingName );
02477         
02478         if ( err != noErr )
02479         {
02480             setTextEncodingConversionError( bsEncodingName, BIGSTRING( "" ), (long) err );
02481             
02482             return ( false );
02483         }
02484         
02485         *encodingId = (long) oneEncoding;
02486         
02487     #endif
02488 
02489     #ifdef WIN95VERSION
02490 
02491         HRESULT err;
02492         IMultiLanguage2 * pMultiLanguage;
02493         MIMECSETINFO setInfo;
02494         wchar_t ianaName[ 512 ];
02495         long lenIanaName;
02496 
02497         lowertext( (ptrbyte) (bsEncodingName + 1), (long) bsEncodingName[ 0 ] );
02498 
02499         if ( equalstrings( bsEncodingName, BIGSTRING ("\x06" "utf-16") ) )
02500         {
02501             *encodingId = 1200;
02502             
02503             return (true);
02504         }
02505 
02506         initCOM();
02507 
02508         err = CoCreateInstance(
02509                 &CLSID_CMultiLanguage, 
02510                 NULL,
02511                 CLSCTX_INPROC_SERVER,
02512                 &IID_IMultiLanguage2,
02513                 (void **) &pMultiLanguage );
02514 
02515         if ( FAILED( err ) )
02516         {
02517             setTextEncodingConversionError( bsEncodingName, BIGSTRING( "" ), err );
02518             
02519             return ( false );
02520         }
02521 
02522         copyPStringToWide( bsEncodingName, &lenIanaName, ianaName );
02523 
02524         err = pMultiLanguage->lpVtbl->GetCharsetInfo( pMultiLanguage, ianaName, &setInfo );
02525         if ( FAILED( err ) )
02526         {
02527             setTextEncodingConversionError( bsEncodingName, BIGSTRING( "" ), kTextUnsupportedEncodingErr );
02528             
02529             pMultiLanguage->lpVtbl->Release( pMultiLanguage );
02530             
02531             return ( false );
02532         }
02533 
02534         *encodingId = (long)(setInfo.uiInternetEncoding);
02535 
02536         pMultiLanguage->lpVtbl->Release( pMultiLanguage );
02537 
02538     #endif
02539     
02540     return (true);
02541 }
02542 
02543 /*
02544     determine if the specified character set is recognized by the OS
02545     bsEncodingName is an IANA-friendly name like "utf-8" , "macintosh", or "iso-8859-1"
02546 */
02547 boolean isTextEncodingAvailable( bigstring bsEncodingName )
02548 {
02549     long encodingId;
02550     boolean fl;
02551     
02552     disablelangerror();
02553     
02554     fl = getTextEncodingIDFromIANA( bsEncodingName, &encodingId );
02555     
02556     enablelangerror();
02557     
02558     return ( fl );
02559 }
02560 
02561 static boolean converttextencoding( Handle h, Handle hresult, const long inputcharset, const long outputcharset, long * OSStatusCode )
02562 {
02563 #ifdef MACVERSION /*Mac character conversion common routine*/
02564 
02565     TECObjectRef converter;     
02566     OSStatus status;
02567     ByteCount ctorigbytes, ctoutputbytes, ctflushedbytes;       
02568     long sizeoutputbuffer;
02569     long pullBytes = 0;
02570     long lentext = gethandlesize (h);
02571 
02572     status = TECCreateConverter (&converter, inputcharset, outputcharset);
02573     if ( status != noErr ) {
02574         TECDisposeConverter (converter);
02575         *OSStatusCode = (long) status;
02576         return ( false );
02577     }
02578 
02579     sizeoutputbuffer = lentext * 4;
02580 
02581     if (sizeoutputbuffer < 32) /*docs say use 32 minimum*/
02582         sizeoutputbuffer = 32;
02583 
02584     if (!sethandlesize (hresult, sizeoutputbuffer)) {  // out of memory
02585         TECDisposeConverter (converter);
02586         return (false);
02587     }
02588 
02589     // 2005-08-26 --- kw better bytemark detecting
02590     // see http://en.wikipedia.org/wiki/Byte_Order_Mark
02591     if (inputcharset == kCFStringEncodingUTF8) // we handle utf-8 input
02592     {
02593         if (    (*h) [0] == '\xEF'
02594              && (*h) [1] == '\xBB'
02595              && (*h) [2] == '\xBF')
02596                 pullBytes = 3;
02597     }
02598     else
02599     {
02600         if (inputcharset == kTextEncodingUnicodeDefault) // utf-16
02601         {
02602             if (    (   (*h) [0] == '\xEF'
02603                      && (*h) [1] == '\xFF')
02604                 ||  (   (*h) [0] == '\xFF'
02605                      && (*h) [1] == '\xFE'))
02606                 pullBytes = 2;
02607         }
02608     }
02609 
02610     lentext = gethandlesize (h) - pullBytes;
02611 
02612     status = TECConvertText( converter, (ConstTextPtr)(*h + pullBytes), lentext, &ctorigbytes, (TextPtr)(*hresult), sizeoutputbuffer, &ctoutputbytes );
02613     
02614     if ( status != noErr )
02615     {
02616         TECDisposeConverter (converter);
02617         
02618         *OSStatusCode = (long) status;
02619         return ( false );
02620     }
02621 
02622     TECFlushText (converter, (TextPtr)(*hresult), sizeoutputbuffer, &ctflushedbytes);
02623 
02624     TECDisposeConverter (converter);
02625 
02626     sethandlesize (hresult, ctoutputbytes + ctflushedbytes);
02627     
02628     return (true);
02629 
02630 #endif /*end Mac character conversion routine(s)*/
02631 
02632 #ifdef WIN95VERSION
02633 
02634     long lentext;
02635     boolean flResult;
02636 
02637     lentext = gethandlesize (h);
02638     
02639     switch ( inputcharset ) {
02640         
02641         case 1200:
02642         case 0: /* utf-16le, a.k.a. "unicode" on windows, not handled as a code page. */
02643 
02644             sethandlesize (h,lentext + 2);
02645 
02646             (*h) [lentext] = '\0';
02647             (*h) [lentext + 1] = '\0';
02648 
02649             flResult = UnicodeToAnsi( h, hresult, outputcharset, OSStatusCode );
02650 
02651             if ( flResult && ( (*h) [0] == '\xFF') )
02652                 pullfromhandle (hresult,0, 1, NULL);  /* Pop off the BOM */
02653 
02654             break;
02655 
02656         default: {
02657 
02658             switch ( outputcharset ) {
02659                 case 1200:
02660                 case 0: /* utf-16le, a.k.a. "unicode" on windows, not handled as a code page */
02661 
02662                     flResult = AnsiToUnicode( h, hresult, inputcharset, OSStatusCode );
02663 
02664                     break;
02665                 
02666                 default: {
02667                     Handle htemp;
02668 
02669                     newemptyhandle (&htemp);
02670 
02671                     sethandlesize (h, lentext + 1);
02672                     (*h) [lentext] = '\0';
02673 
02674                     flResult = AnsiToUnicode (h, htemp, inputcharset, OSStatusCode );
02675 
02676                     if ( flResult && UnicodeToAnsi( htemp, hresult, outputcharset, OSStatusCode ) ) {
02677                         
02678                         if ((*hresult) [0] == '\xFF')
02679                             pullfromhandle (hresult, 0, 1, NULL);  /* pop BOM ? */
02680                         
02681                         } /* unicodetoansi */
02682                     else
02683                         flResult = false;
02684 
02685                     disposehandle (htemp);
02686 
02687                     } /* case default */
02688 
02689                 } /* switch outputcharset */
02690 
02691             } /* case default */
02692         
02693         } /* switch inputcharset */
02694     
02695     return ( flResult );
02696 
02697 #endif
02698     } /*converttextencoding*/
02699 
02700 
02701 boolean convertCharset( Handle hString, Handle hresult, bigstring charsetIn, bigstring charsetOut )
02702 {
02703     long err;
02704     
02705     #ifdef MACVERSION
02706         
02707         TextEncoding teInputSet, teOutputSet;
02708 
02709     #endif
02710 
02711     #ifdef WIN95VERSION
02712 
02713         long teInputSet, teOutputSet;
02714 
02715         initCOM();
02716 
02717     #endif
02718     
02719     if ( ! getTextEncodingIDFromIANA( charsetIn, (long *) &teInputSet ) )
02720         return (false);
02721     
02722     if ( ! getTextEncodingIDFromIANA( charsetOut, (long *) &teOutputSet ) )
02723         return (false);
02724     
02725     if ( ! converttextencoding( hString, hresult, (long) teInputSet, (long) teOutputSet, &err ) )
02726     {
02727         setTextEncodingConversionError( charsetIn, charsetOut, err );
02728         
02729         return ( false );
02730     }
02731     
02732     return ( true );
02733 }
02734 
02735 
02736 boolean utf16toansi( Handle h, Handle hresult ) {
02737 
02738     /*
02739     7.0b42 PBS: convert from UTF-16 to iso-8859-1 character sets.
02740     */
02741     
02742     #ifdef WIN95VERSION
02743     
02744         long err;
02745         long lentext = gethandlesize (h);
02746 
02747         sethandlesize (h, lentext + 2);
02748 
02749         (*h) [lentext] = '\0';
02750 
02751         (*h) [lentext + 1] = '\0';
02752 
02753         if ( ! UnicodeToAnsi (h, hresult, CP_ACP, &err) )
02754         
02755             goto error;
02756 
02757         if ((*h) [0] == '\xFF')
02758 
02759             pullfromhandle (hresult, 0, 1, NULL); /*Pop byte order mark*/
02760         
02761     #endif
02762     
02763     #ifdef MACVERSION
02764         
02765         long err;
02766         
02767         if ( !converttextencoding( h, hresult, kTextEncodingUnicodeDefault, kTextEncodingWindowsLatin1, &err ) )
02768         
02769             goto error;
02770 
02771     #endif
02772 
02773     return (true);
02774     
02775     
02776     error:
02777         
02778         setTextEncodingConversionError( cs_utf16, cs_iso88591, (long) err );
02779         
02780         return ( false );
02781     
02782     } /*utf16toansi*/
02783 
02784 
02785 boolean utf8toansi (Handle h, Handle hresult) {
02786 
02787     /*
02788     70b42 PBS: convert from UTF-8 to ANSI.
02789     */
02790     
02791     long err;
02792     
02793     #ifdef WIN95VERSION
02794 
02795         long lentext = gethandlesize (h);
02796 
02797         Handle htemp;
02798 
02799         newemptyhandle (&htemp);
02800 
02801         sethandlesize (h, lentext + 1);
02802 
02803         (*h) [lentext] = '\0';
02804 
02805         if ( ! AnsiToUnicode (h, htemp, CP_UTF8, &err ) ) /*Convert to UTF-16*/
02806         {
02807             setTextEncodingConversionError( cs_utf8, cs_utf16, err );
02808             
02809             return ( false );
02810         }
02811 
02812         if ( ! UnicodeToAnsi( htemp, hresult, CP_ACP, &err ) ) /*Convert from UTF-16 to ANSI*/
02813         {
02814             setTextEncodingConversionError( cs_utf16, cs_iso88591, err);
02815             
02816             return ( false );
02817         }
02818 
02819         if ((*htemp) [0] == '\xFF')
02820 
02821             pullfromhandle (hresult, 0, 1, NULL); /*Pop byte order mark*/
02822 
02823         disposehandle (htemp);
02824         
02825     #endif
02826     
02827     #ifdef MACVERSION
02828         
02829         if ( !converttextencoding( h, hresult, kCFStringEncodingUTF8, kTextEncodingWindowsLatin1, &err ) )
02830         {
02831             setTextEncodingConversionError( cs_utf8, cs_iso88591, err );
02832             
02833             return (false);
02834         }
02835 
02836     #endif
02837 
02838     return (true);
02839     
02840     } /*utf8toansi*/
02841 
02842 
02843 boolean ansitoutf8 (Handle h, Handle hresult) {
02844 
02845     /*
02846     7.0b42 PBS: convert from ANSI to UTF-8.
02847     */
02848     
02849     long err;
02850     
02851     #ifdef WIN95VERSION
02852 
02853         Handle htemp;
02854         long lentext = gethandlesize (h);
02855 
02856         sethandlesize (h, lentext + 1);
02857 
02858         (*h) [lentext] = '\0';
02859 
02860         newemptyhandle (&htemp);
02861 
02862         if ( ! AnsiToUnicode( h, htemp, CP_ACP, &err ) ) /*convert to UTF-16*/
02863         {
02864             setTextEncodingConversionError( cs_iso88591, cs_utf16, err );
02865             
02866             return ( false );
02867         }
02868         
02869         if ( ! UnicodeToAnsi( htemp, hresult, CP_UTF8, &err ) ) /*convert from UTF-16 to UTF-8*/
02870         {
02871             setTextEncodingConversionError( cs_utf16, cs_utf8, err );
02872             
02873             return ( false );
02874         }
02875 
02876         disposehandle (htemp);
02877 
02878         lentext = gethandlesize (hresult);
02879     
02880     #endif
02881     
02882     #ifdef MACVERSION
02883     
02884         if ( !converttextencoding( h, hresult, kTextEncodingWindowsLatin1, kCFStringEncodingUTF8, &err ) )
02885         {
02886             setTextEncodingConversionError( cs_iso88591, cs_utf8, err );
02887             
02888             return ( false );
02889         }
02890     
02891     #endif
02892 
02893     return (true);
02894     } /*ansitoutf8*/
02895 
02896 
02897 boolean ansitoutf16 (Handle h, Handle hresult) {
02898 
02899     /*
02900     7.0b42 PBS: convert from ANSI to UTF-16.
02901     */
02902     
02903     long err;
02904     
02905     #ifdef WIN95VERSION
02906     
02907         long lentext = gethandlesize (h);
02908 
02909         sethandlesize (h, lentext + 1);
02910 
02911         (*h) [lentext] = '\0';
02912 
02913         if ( ! AnsiToUnicode( h, hresult, CP_ACP, &err ) )
02914         {
02915             setTextEncodingConversionError( cs_iso88591, cs_utf16, err );
02916             
02917             return ( false );
02918         }
02919     
02920     #endif
02921     
02922     #ifdef MACVERSION
02923     
02924         if ( !converttextencoding( h, hresult, kTextEncodingWindowsLatin1, kTextEncodingUnicodeDefault, &err ) )
02925         {
02926             setTextEncodingConversionError( cs_iso88591, cs_utf16, err );
02927             
02928             return ( false );
02929         }
02930 
02931     #endif
02932 
02933     return (true);
02934     } /*ansitoutf8*/
02935 
02936 
02937 boolean pullstringsuffix (bigstring bssource, bigstring bssuffix, unsigned char chsuffix) {
02938 
02939     /*
02940     7.0.2b1 Radio PBS: get the suffix from a string.
02941     On return, bssource lacks the suffix and the suffix character.
02942     bssuffix contains the suffix minus the suffix character.
02943     */
02944 
02945     short lensource = stringlength (bssource);
02946     short ct = lensource;
02947     char ch;
02948     boolean fl = false;
02949 
02950     copystring (emptystring, bssuffix);
02951 
02952     while (true) {
02953 
02954         if (ct < 1)
02955             break;
02956 
02957         ch = bssource [ct];
02958     
02959         if (ch == chsuffix) {
02960 
02961             fl = true;
02962 
02963             break;
02964             } /*if*/
02965 
02966         insertchar (ch, bssuffix);
02967 
02968         ct--;
02969         } /*while*/
02970 
02971     
02972     if (fl)
02973 
02974         setstringlength (bssource, (stringlength (bssource) - stringlength (bssuffix)) - 1);
02975 
02976     else
02977 
02978         copystring (emptystring, bssuffix);
02979         
02980     return (fl);
02981     } /*pullsuffix*/
02982 
02983 
02984 boolean macromantoutf8 (Handle h, Handle hresult) {
02985 
02986     /*
02987     2006-05-03 creedon: fixed bug introduced in changeover to use converttextencoding function, reverse encIn and encOut
02988                    values
02989     2006-02-24 creedon: convert from Mac Roman character set to UTF-8, cribbed from ansitoutf8
02990     */
02991     
02992     long err;
02993     long encIn, encOut;
02994     
02995     #ifdef WIN95VERSION
02996     
02997         encIn = CP_UTF8;
02998         encOut = 10000;
02999     
03000     #endif
03001     
03002     #ifdef MACVERSION
03003         
03004         encIn = kTextEncodingMacRoman;
03005         encOut = kCFStringEncodingUTF8;
03006     
03007     #endif
03008     
03009     if ( !converttextencoding( h, hresult, encIn, encOut, &err ) )
03010     {
03011         setTextEncodingConversionError( cs_utf8, cs_macintosh, err );
03012         
03013         return ( false );
03014     }
03015 
03016     return (true);
03017     } /* macromantoutf8 */
03018 
03019 
03020 boolean utf8tomacroman (Handle h, Handle hresult) {
03021 
03022     /*
03023     2006-02-26 creedon: convert from UTF-8 character set to Mac Roman, cribbed from utf8toansi
03024     */
03025     
03026     long err;
03027     long encIn, encOut;
03028     
03029     #ifdef WIN95VERSION
03030     
03031         encIn = CP_UTF8;
03032         encOut = 10000;
03033     
03034     #endif
03035     
03036     #ifdef MACVERSION
03037         
03038         encIn = kCFStringEncodingUTF8;
03039         encOut = kTextEncodingMacRoman;
03040     
03041     #endif
03042     
03043     if ( !converttextencoding( h, hresult, encIn, encOut, &err ) )
03044     {
03045         setTextEncodingConversionError( cs_utf8, cs_macintosh, err );
03046         
03047         return ( false );
03048     }
03049     
03050     return (true);
03051     } /* utf8tomacroman */
03052 
03053 
03054 
03055 void initstrings (void) {
03056     
03057     register short i;
03058 
03059     for (i = 0; i < 256; i++)
03060         lowercasetable[i] = tolower (i);
03061     
03062     clearbytes (&parseparams, longsizeof (parseparams));
03063     
03064     for (i = 1; i <= ctdirections; i++) {
03065         
03066         bigstring bs;
03067         
03068         getstringlist (directionlistnumber, i, bs);
03069         
03070         newheapstring (bs, &dirstrings [i - 1]);
03071         } /*for*/
03072     } /*initstrings*/

Generated on Wed May 31 18:20:02 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6