oppack.c

Go to the documentation of this file.
00001 
00002 /*  $Id: oppack.c 1287 2006-04-16 21:30:34Z andreradke $    */
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 #include "memory.h"
00032 #include "font.h"
00033 #include "quickdraw.h"
00034 #include "strings.h"
00035 #include "ops.h"
00036 #include "op.h"
00037 #include "opinternal.h"
00038 #include "byteorder.h"  /* 2006-04-08 aradke: endianness conversion macros */
00039 
00040 
00041 typedef struct tylinetableitem {
00042     
00043     short flags;
00044     
00045     long lenrefcon; /*number of bytes that follow -- the refcon information*/
00046     } tylinetableitem, *ptrlinetable, **hdllinetable;
00047 
00048 typedef enum tylinetableitemflags {
00049 
00050 #ifndef SWAP_BYTE_ORDER
00051     flexpanded = 0x8000, /*was the line expanded when the outline was closed?*/
00052     flopenwindow = 0x4000, /*was the linked window open when its owner was closed?*/
00053     appbit0 = 0x2000, /*application-defined bit*/
00054     appbit1 = 0x1000, /*application-defined bit*/
00055     fllocked = 0x0800, /*is the line locked?*/
00056     flcomment = 0x0400, /*is this line a comment?*/
00057     flbreakpoint = 0x0200 /*is a breakpoint set on this line?*/
00058 #else
00059     flexpanded = 0x0080, /*was the line expanded when the outline was closed?*/
00060     flopenwindow = 0x0040, /*was the linked window open when its owner was closed?*/
00061     appbit0 = 0x0020, /*application-defined bit*/
00062     appbit1 = 0x0010, /*application-defined bit*/
00063     fllocked = 0x0008, /*is the line locked?*/
00064     flcomment = 0x0004, /*is this line a comment?*/
00065     flbreakpoint = 0x0002 /*is a breakpoint set on this line?*/
00066 #endif
00067     } tylinetableitemflags;
00068 
00069 #define macplatform 'mac '
00070 #define winplatform 'win '
00071 
00072 #ifdef MACVERSION
00073     #define thisplatform macplatform
00074     #define diskchcomment           ((byte) 0xab)   /* '' */
00075     #define diskchendcomment        ((byte) 0xbb)
00076     #define diskchopencurlyquote    ((byte) 0x93)
00077     #define diskchclosecurlyquote   ((byte) 0x94)
00078     #define diskchtrademark         ((byte) 0x99)
00079     #define diskchnotequals         ((byte) 0xad)   /* '' */
00080     #define diskchdivide            ((byte) 0xf7)   /* '' */
00081 #endif
00082 #ifdef WIN95VERSION
00083     #define thisplatform winplatform
00084     #define diskchcomment           ((byte) 0xc7)   /* '' */
00085     #define diskchendcomment        ((byte) 0xc8)   /* '' */
00086     #define diskchopencurlyquote    ((byte) 0xd2)   /* '' */
00087     #define diskchclosecurlyquote   ((byte) 0xd3)   /* '' */
00088     #define diskchtrademark         ((byte) 0xaa)   /* '' */
00089     #define diskchnotequals         ((byte) 0xad)   /* '' */
00090     #define diskchdivide            ((byte) 0xd6)   /* '' */
00091     #define diskchellipses          ((byte) 0xc9)   /* '' */
00092 
00093     static byte bsellipses [] = "\x03...";
00094 #endif
00095 
00096 #define opversionnumber 2
00097 
00098 #define hibyte(x) (x & 0xff00)
00099     
00100     
00101 typedef struct tyversion2diskheader {
00102     
00103     short versionnumber; /*important, this structure is saved on disk*/
00104     
00105     long sizelinetable; /*number of bytes in the linetable section of handle*/
00106     
00107     long sizetext; /*number of bytes in the text portion of handle*/
00108     
00109     short lnumcursor; 
00110     
00111 #ifdef MACVERSION
00112     tylinespacing linespacing;
00113 #endif
00114 #ifdef WIN95VERSION
00115     short linespacing;
00116 #endif
00117     
00118     short lineindent;
00119     
00120     diskfontstring fontname; 
00121     
00122     short fontsize, fontstyle;
00123     
00124     short vertmin, vertmax, vertcurrent; /*for structs that don't get their own file*/
00125     
00126     short horizmin, horizmax, horizcurrent;
00127     
00128     unsigned long timecreated, timelastsave;
00129     
00130     unsigned long ctsaves;
00131     
00132     boolean fltextmode;
00133     
00134     diskrect windowrect; /*the size and position of the window that displays the outline*/
00135     
00136     long outlinesignature; /*client info*/
00137     
00138     RGBColor backcolor;
00139     
00140     RGBColor forecolor;
00141     
00142     OSType platform; /*Mac or Win*/
00143     
00144     short lnumcursor_hiword;
00145     
00146     short vertcurrent_hiword; //vert min, max aren't really used
00147     
00148     short horizcurrent_hiword; //horiz min, max aren't really used
00149     
00150     short waste [3]; /*room to grow*/
00151     } tyversion2diskheader;
00152 
00153 
00154 typedef struct tyoppackinfo {
00155 
00156     handlestream *packstream;
00157     
00158     boolean flpackcomments;
00159     } tyoppackinfo, *ptroppackinfo;
00160 
00161 
00162 static boolean outtablevisit (hdlheadrecord hnode, ptrvoid refcon) {
00163     
00164     /*
00165     4.1b7 dmb: we should never dispose of the packhandle.
00166     oppack takes care of that.
00167     
00168     5.1.3 dmb: use pushhandle to add refcon data; don't lock refcon while 
00169     enlarging packhandle
00170     */
00171 
00172     register hdlheadrecord hn = hnode;
00173     register Handle hrefcon = (**hn).hrefcon;
00174     register long lenrefcon;
00175     ptroppackinfo packinfo = (ptroppackinfo) refcon;
00176     tylinetableitem item;
00177     
00178     clearbytes (&item, sizeof (item));
00179     
00180     item.flags |= flexpanded * (**hn).flexpanded;
00181     
00182     item.flags |= flopenwindow * (**hn).tmpbit;
00183     
00184     item.flags |= appbit0 * (**hn).appbit0;
00185     
00186     item.flags |= appbit1 * (**hn).appbit1;
00187     
00188     item.flags |= fllocked * (**hn).fllocked;
00189     
00190     item.flags |= flcomment * (**hn).flcomment;
00191     
00192     item.flags |= flbreakpoint * (**hn).flbreakpoint;
00193     
00194     lenrefcon = gethandlesize (hrefcon); /*0 if it's nil*/
00195 
00196     item.lenrefcon = conditionallongswap (lenrefcon);
00197 
00198     (**hnode).tmpbit = false;
00199     
00200     if (!writehandlestream ((*packinfo).packstream, &item, sizeof (item))) {
00201     
00202         /*4.1b7 dmb: our caller manages this - disposehandle (packhandle);*/
00203         
00204         return (false);
00205         }
00206     
00207     if (lenrefcon > 0) { /*something stored in the refcon field*/
00208         
00209         if (!writehandlestreamhandle ((*packinfo).packstream, hrefcon)) {
00210             
00211             /*4.1b7 dmb: our caller manages this - disposehandle (packhandle);*/
00212             
00213             return (false);
00214             }
00215         }
00216         
00217     return (true);
00218     } /*outtablevisit*/
00219 
00220 
00221 static boolean opoutlinetotable (hdlheadrecord hnode, handlestream *packstream, long *ctbytes) {
00222     
00223     /*
00224     traverse the current outline, producing a table of information 
00225     with one element for each line in the outline.  append that table
00226     to the end of the indicated handle and return the number of bytes
00227     added to the handle.
00228     
00229     return false if there was a memory error.
00230     */
00231     
00232     register long origsize;
00233     tyoppackinfo packinfo;
00234     
00235     *ctbytes = 0;
00236     
00237     origsize = (*packstream).eof;
00238     
00239     packinfo.packstream = packstream;
00240     
00241     if (!opsiblingvisiter (hnode, false, &outtablevisit, &packinfo))
00242         return (false);
00243         
00244     *ctbytes = (*packstream).eof - origsize;
00245     
00246     return (true);
00247     } /*opoutlinetotable*/
00248 
00249 
00250 static boolean pushdiskchar (byte ch, handlestream *deststream) {
00251 
00252     /*
00253     insert the character at the end of a pascal string.
00254     map cross-platform disk characters to machine-specific chars
00255 
00256     5.0b11 dmb: we're now only called when mapping from the other
00257     platform the diskch constants are the other flatform's
00258     */
00259 
00260     switch (ch) {
00261         case diskchcomment:
00262             ch = chcomment;
00263             break;
00264         
00265         case diskchendcomment:
00266             ch = chendcomment;
00267             break;
00268         
00269         case diskchopencurlyquote:
00270             ch = chopencurlyquote;
00271             break;
00272 
00273         case diskchclosecurlyquote:
00274             ch = chclosecurlyquote;
00275             break;
00276         
00277         case diskchtrademark:
00278             ch = chtrademark;
00279             break;
00280 
00281         case diskchdivide:
00282             ch = chdivide;
00283             break;
00284         
00285     #ifndef MACVERSION
00286         case diskchnotequals:
00287             if (!writehandlestreamchar (deststream, '!'))
00288                 return (false);
00289             
00290             ch = '=';
00291             break;
00292         
00293         case diskchellipses:
00294             return (writehandlestreamstring (deststream, bsellipses));
00295     #endif
00296 
00297         default:
00298             break;
00299         }
00300     
00301     return (writehandlestreamchar (deststream, ch));
00302     } /*pushdiskchar*/
00303 
00304 
00305 #if 0
00306 
00307 static boolean xxxpushstringtodisk (bigstring bssource, bigstring bsdest) {
00308 
00309     /*
00310     insert the source string at the end of the destination string.
00311     map machine-specific disk characters to cross-platform chars
00312     */
00313     
00314     short lensource = stringlength (bssource);
00315     short lendest = stringlength (bsdest);
00316     register byte *psource, *pdest;
00317     byte ch;
00318     
00319     if ((lensource + lendest) > lenbigstring) /*resulting string would be too long*/
00320         return (false);
00321         
00322     pdest = stringbaseaddress (bsdest) + lendest;
00323     
00324     psource = stringbaseaddress (bssource);
00325     
00326     setstringlength (bsdest, lendest + lensource);
00327     
00328     while (lensource--) {
00329         
00330         ch = *psource++;
00331 
00332         /*
00333         switch (ch) {
00334             case chcomment:
00335                 ch = diskchcomment;
00336                 break;
00337             
00338             case chendcomment:
00339                 ch = diskchendcomment;
00340                 break;
00341             
00342             case chopencurlyquote:
00343                 ch = diskchopencurlyquote;
00344                 break;
00345 
00346             case chclosecurlyquote:
00347                 ch = diskchclosecurlyquote;
00348                 break;
00349             
00350             case chtrademark:
00351                 ch = diskchtrademark;
00352                 break;
00353 
00354             case chnotequals:
00355                 ch = diskchnotequals;
00356                 break;
00357             
00358             case chdivide:
00359                 ch = diskchdivide;
00360                 break;
00361             
00362             default:
00363                 break;
00364             }
00365         */
00366 
00367         *pdest++ = ch;
00368         }
00369     
00370     return (true);
00371     } /*pushstringtodisk*/
00372 
00373 #endif
00374 
00375 
00376 static boolean outtextvisit (hdlheadrecord hnode, ptroppackinfo packinfo) {
00377     
00378     /*
00379     2.1b3 dmb: account for the fact that the leading tabs and trailing 
00380     return may overflow our 255-character limit
00381     
00382     2.1b5 dmb: added option to skip comment text
00383     
00384     4.1b7 dmb: we should never dispose of the packhandle.
00385     oppack takes care of that.
00386 
00387     5.0b11 dmb: don't map character when packing. can lose info, screw 
00388     clipboard
00389     */
00390     
00391     register short level = (**hnode).headlevel;
00392     bigstring bs;
00393     
00394     filledstring (chtab, level, bs);
00395     
00396     if (!writehandlestreamstring ((*packinfo).packstream, bs)) //push the tabs by themself
00397         goto error;
00398     
00399     if ((*packinfo).flpackcomments || !opnestedincomment (hnode)) {
00400         
00401         if (!writehandlestreamhandle ((*packinfo).packstream, (**hnode).headstring)) //push the head text
00402             goto error;
00403         }
00404     
00405     if (!writehandlestreamchar ((*packinfo).packstream, chreturn)) //push the cr terminator
00406         goto error;
00407 
00408     return (true);
00409     
00410     error: {
00411         
00412         /*4.1b7 dmb: our caller manages this - disposehandle (packhandle);*/
00413         
00414         return (false);
00415         }
00416     } /*outtextvisit*/
00417     
00418 
00419 static boolean opoutlinetotext (hdlheadrecord hnode, handlestream *textstream, long *ctbytes) {
00420     
00421     /*
00422     convert the outline into a block of tab-indented text, each
00423     line ended by a carriage return.  suitable for saving to disk
00424     because we convert the whole outline, all level-0 heads in
00425     the current outline.
00426     
00427     push the resulting text at the end of the indicated handle and
00428     return in ctbytes the number of bytes added to the handle.
00429     
00430     return false if there was a memory allocation error.
00431     */
00432     
00433     register long origbytes;
00434     tyoppackinfo packinfo;
00435     
00436     origbytes = (*textstream).eof;
00437     
00438     *ctbytes = 0;
00439     
00440     packinfo.packstream = textstream;
00441     
00442     packinfo.flpackcomments = true;
00443     
00444     if (!opsiblingvisiter (hnode, false, (opvisitcallback) &outtextvisit, &packinfo))
00445         return (false);
00446     
00447     *ctbytes = (*textstream).eof - origbytes;
00448     
00449     return (true);
00450     } /*opoutlinetotext*/
00451 
00452 
00453 boolean oppack (Handle *hpackedoutline) {
00454     
00455     /*
00456     create a packed, contiguous version of the current outline record.
00457     
00458     DW 3/25/90: if hpackedoutline comes in non-nil, we just append our
00459     stuff to the end of the handle, we don't allocate a new one.
00460     
00461     dmb 10/16/90: don't dispose of handle if we didn't allocate it
00462     
00463     dmb 2/8/91: flush edit buffer if in text mode
00464     
00465     dmb 3/1/91: deal with hoists
00466     
00467     4/9/93 dmb: resize the packedoutline handle really large and back again 
00468     before starting to avoid potentially many, many heap compactions while 
00469     expanding it for real
00470     
00471     4.1b7 dmb: fixed double dispose bug. if our caller allocated the handle
00472     we do not dispose it on error, as was originally intended.
00473 
00474     5.0b11 dmb: added platform logic. don't map characters when packing
00475     */
00476     
00477     register hdloutlinerecord ho = outlinedata;
00478     register hdlheadrecord hsummit;
00479     register Handle h;
00480     register long ixheader;
00481     handlestream packstream;
00482     tyversion2diskheader header;
00483     boolean flallocated = false;
00484     boolean flpoppedhoists = false;
00485     boolean flerror = false;
00486     long lnumcursor;
00487     
00488     h = *hpackedoutline; /*copy into register*/
00489     
00490     clearbytes (&header, sizeof (header)); /*assure all bits set to 0*/
00491     
00492     if (h == nil) { /*the normal case, allocate a new handle*/
00493         
00494         if (!newgrowinghandle (5 * 1024, hpackedoutline)) //start with non-empty handle
00495             return (false);
00496         
00497         h = *hpackedoutline;
00498         
00499         flallocated = true;
00500         
00501         openhandlestream (h, &packstream);
00502         
00503         packstream.pos = packstream.eof = sizeof (header);
00504         }
00505     else {
00506         
00507         openhandlestream (h, &packstream);
00508         
00509         packstream.pos = packstream.eof;
00510         
00511         if (!writehandlestream (&packstream, &header, sizeof (header)))
00512             return (false);
00513         }
00514     
00515     ixheader = packstream.pos - sizeof (header); //we're pointing past header now
00516     
00517     flpoppedhoists = oppopallhoists ();
00518     
00519     header.versionnumber = conditionalshortswap(opversionnumber);
00520     
00521     header.platform = conditionallongswap (thisplatform);
00522 
00523     opgetnodeline ((**ho).hbarcursor, &lnumcursor);
00524     
00525     memlongtodiskwords (lnumcursor, header.lnumcursor, header.lnumcursor_hiword);
00526     
00527     header.linespacing = conditionalenumswap((**ho).linespacing);
00528     
00529     header.lineindent = conditionalshortswap((**ho).lineindent);
00530     
00531     header.fltextmode = (**ho).fltextmode;
00532     
00533     header.vertmin = conditionalshortswap((**ho).vertscrollinfo.min);
00534     
00535     header.vertmax = conditionalshortswap((**ho).vertscrollinfo.max);
00536     
00537     memlongtodiskwords ((**ho).vertscrollinfo.cur, header.vertcurrent, header.vertcurrent_hiword);
00538     
00539     header.horizmin = conditionalshortswap((**ho).horizscrollinfo.min);
00540     
00541     header.horizmax = conditionalshortswap((**ho).horizscrollinfo.max);
00542     
00543     memlongtodiskwords ((**ho).horizscrollinfo.cur, header.horizcurrent, header.horizcurrent_hiword);
00544     
00545     header.timecreated = conditionallongswap((**ho).timecreated);
00546     
00547     header.timelastsave = conditionallongswap((**ho).timelastsave);
00548     
00549     /*timestamp (&header.timelastsave);*/ /*dmb 4.1b13: don't stamp it; opdirty sets it as true mode date*/
00550     
00551     header.ctsaves = conditionallongswap(++(**ho).ctsaves);
00552     
00553     header.forecolor = (**ho).forecolor;
00554     
00555     memtodiskshort (header.forecolor.red);
00556     memtodiskshort (header.forecolor.green);
00557     memtodiskshort (header.forecolor.blue);
00558     
00559     header.backcolor = (**ho).backcolor;
00560     
00561     memtodiskshort (header.backcolor.red);
00562     memtodiskshort (header.backcolor.green);
00563     memtodiskshort (header.backcolor.blue);
00564     
00565     diskgetfontname ((**ho).fontnum, header.fontname);
00566     
00567     header.fontsize = conditionalshortswap((**ho).fontsize);
00568     
00569     header.fontstyle = conditionalshortswap((**ho).fontstyle);
00570     
00571     recttodiskrect (&(**ho).windowrect, &header.windowrect);
00572     
00573     header.outlinesignature = conditionallongswap((**ho).outlinesignature);
00574     
00575     hsummit = (**ho).hsummit; /*copy into register*/
00576     
00577     opwriteeditbuffer (); /*if a headline is being edited, update text handle*/
00578     
00579     if (!opoutlinetotext (hsummit, &packstream, &header.sizetext)) {
00580         
00581         flerror = true;
00582         
00583         goto exit;
00584         }
00585         
00586     if (!opoutlinetotable (hsummit, &packstream, &header.sizelinetable)) {
00587     
00588         flerror = true;
00589         
00590         goto exit;
00591         }
00592     
00593     memtodisklong (header.sizetext);
00594     memtodisklong (header.sizelinetable);
00595     
00596     /*move the header into handle*/ {
00597         
00598         register ptrbyte p;
00599         
00600         p = BIGSTRING (*h);
00601         
00602         p += ixheader;
00603         
00604         moveleft (&header, p, sizeof (header));
00605         }
00606     
00607     exit:
00608     
00609     if (flpoppedhoists)
00610         oprestorehoists ();
00611     
00612     closehandlestream (&packstream);
00613     
00614     if (flerror) {
00615         
00616         if (flallocated)
00617             disposehandle (h);
00618         
00619         return (false);
00620         }
00621     
00622     return (true);
00623     } /*oppack*/
00624 
00625 
00626 boolean oppackoutline (hdloutlinerecord houtline, Handle *hpackedoutline) {
00627     
00628     boolean fl;
00629     
00630     oppushoutline (houtline);
00631     
00632     fl = oppack (hpackedoutline);
00633     
00634     oppopoutline ();
00635     
00636     return (fl);
00637     } /*oppackoutline*/
00638 
00639 
00640 static boolean intablevisit (hdlheadrecord hnode, ptrvoid refcon) {
00641     
00642     /*
00643     5.1.5b9 dmb: validate expanded bit in case structure changes with overflow
00644     */
00645     
00646     register hdlheadrecord hn = hnode;
00647     ptroppackinfo packinfo = (ptroppackinfo) refcon;
00648     register long lenrefcon;
00649     Handle hrefcon;
00650     tylinetableitem item;
00651     hdlheadrecord hup, hleft;
00652     
00653     if (athandlestreameof ((*packinfo).packstream)) // ran out of line items
00654         return (true);
00655     
00656     readhandlestream ((*packinfo).packstream, &item, sizeof (item));
00657     
00658     hup = (**hn).headlinkup;
00659     
00660     if (hup == hn) { //first in list, can set expandedness
00661     
00662         hleft = (**hn).headlinkleft;
00663         
00664         if ((hleft != hn) && !(**hleft).flexpanded)
00665             (**hn).flexpanded = false;
00666         else
00667             (**hn).flexpanded = (item.flags & flexpanded) != 0;
00668         }
00669     else
00670         (**hn).flexpanded = (**hup).flexpanded;
00671     
00672     (**hn).fllocked = (item.flags & fllocked) != 0;
00673     
00674     (**hn).flcomment = (item.flags & flcomment) != 0;
00675     
00676     (**hn).flbreakpoint = (item.flags & flbreakpoint) != 0;
00677     
00678     (**hn).tmpbit = (item.flags & flopenwindow) != 0;
00679     
00680     (**hn).appbit0 = (item.flags & appbit0) != 0;
00681     
00682     (**hn).appbit1 = (item.flags & appbit1) != 0;
00683     
00684     lenrefcon = conditionallongswap(item.lenrefcon); /*copy into register*/
00685     
00686     if (lenrefcon > 0) { /*link in a refcon node*/
00687     
00688         if (!newclearhandle (lenrefcon, &hrefcon))
00689             return (false);
00690         
00691         readhandlestream ((*packinfo).packstream, *hrefcon, lenrefcon);
00692 
00693         (**hn).hrefcon = hrefcon;
00694         }
00695     
00696     return (true);
00697     } /*intablevisit*/
00698 
00699 
00700 static boolean optabletooutline (handlestream *packstream, hdlheadrecord hsummit) { 
00701 
00702     /*
00703     apply values in table to hsummit outline
00704     */
00705     
00706     tyoppackinfo packinfo;
00707     
00708     packinfo.packstream = packstream;
00709     
00710     return (opsiblingvisiter (hsummit, false, &intablevisit, &packinfo));
00711     } /*optabletooutline*/
00712     
00713 
00714 static short spacesforlevel;
00715 
00716 static short firstindent;
00717 
00718 static boolean fltabindent;
00719 
00720 static void clearindentvalues (boolean flmusttabindent) {
00721     
00722     spacesforlevel = 0;
00723     
00724     firstindent = -1;
00725     
00726     fltabindent = flmusttabindent;
00727     } /*clearindentvalues*/
00728 
00729 
00730 static boolean opgetlinetext (boolean flmapchars, handlestream *textstream, short *level, Handle *htext) {
00731 
00732     /*
00733     extract a line of text from the handle at offset ix.  ix gets bumped to
00734     point at the beginning of the next line.
00735     
00736     the level is the number of ascii 9's at the head of the string.
00737     
00738     12/13/91 dmb: added support for space-indented text import
00739     
00740     3/11/92 dmb: fixed off-by-one error when filling lenbigstring w/out hitting a cr.
00741     
00742     2.1b8 dmb: ignore null characters
00743     
00744     5.0a2 dmb: when overflowing a headline, try to break after a word
00745     
00746     5.0a4 dmb: added *level+1 limit to constrain to correct structure, avoid hang
00747                skip linefeeds after returns
00748 
00749     5.0b11 dmb: map characters when they're from the other platform
00750     */
00751     
00752     handlestream s;
00753     long ct = 0;
00754     register ptrbyte p;
00755     boolean fl;
00756     
00757     if (athandlestreameof (textstream))
00758         return (false);
00759     
00760     if (!newhandle (lenbigstring, htext))
00761         return (false);
00762     
00763     openhandlestream (*htext, &s);
00764     
00765     s.eof = 0; //nothing has actually been written to the 255-byte buffer
00766     
00767     ct = skiphandlestreamchars (textstream, chtab);
00768     
00769     if (ct > 0)
00770         fltabindent = true;
00771     
00772     else {
00773     
00774         ct = skiphandlestreamchars (textstream, chspace);
00775         
00776         if (ct > 0) {
00777             
00778             if (spacesforlevel == 0) /*first run of spaces*/
00779                 spacesforlevel = (short) ct;
00780             
00781             ct = divround (ct, spacesforlevel);
00782             }
00783         }
00784     
00785 /*
00786     while (*p == chtab) { /%count the leading tab chars
00787 
00788         ct++;
00789         
00790         p++;
00791         
00792         ixtext++;
00793         
00794         if (ixtext >= sizetext) /%no text on the line
00795             return (false);
00796         
00797         fltabindent = true;
00798         }
00799 
00800     if (!fltabindent) {
00801         
00802         while (*p == chspace) { /%count the leading tab chars
00803             
00804             ct++;
00805             
00806             p++;
00807             
00808             ixtext++;
00809             
00810             if (ixtext >= sizetext) /%no text on the line
00811                 return (false);
00812             }
00813         
00814         if (ct > 0) {
00815             
00816             if (spacesforlevel == 0) /%first run of spaces
00817                 spacesforlevel = (short) ct;
00818             
00819             ct = divround (ct, spacesforlevel);
00820             }
00821         }
00822 */
00823 
00824     if (firstindent < 0) { /*first line of text*/
00825     
00826         firstindent = (short) ct;
00827         
00828         *level = 0;
00829         }
00830     else {
00831         *level = min (*level + 1, max (0, ct - firstindent));
00832         }
00833     
00834     while ((*textstream).pos < (*textstream).eof) { /*copy the text chars into the string*/
00835         
00836         p = (ptrbyte) (*(*textstream).data + (*textstream).pos);
00837         
00838         if (*p == chreturn) {
00839             
00840             (*textstream).pos++; /*skip over the return; we'll start a new headline*/
00841             
00842             if (*++p == chlinefeed)
00843                 (*textstream).pos++;
00844             
00845             break;
00846             }
00847         
00848         if (*p != chnul) { /*ignore null characters*/
00849             
00850             if (flmapchars)
00851                 fl = pushdiskchar (*p, &s);
00852             else
00853                 fl = writehandlestreamchar (&s, *p);
00854             
00855             if (!fl) {
00856                 
00857                 disposehandle (*htext);
00858                 
00859                 return (false);
00860                 }
00861             }
00862         
00863         (*textstream).pos++;
00864         } /*while*/
00865     
00866     closehandlestream (&s);
00867     
00868     return (true);
00869     } /*opgetlinetext*/
00870 
00871 
00872 static boolean opunpacktexttooutline (long platform, handlestream *packstream, hdlheadrecord *hnode) {
00873     
00874     /*
00875     2/19/91 dmb: call opstart/endinternalchange around this routine to 
00876     avoid building bogus undo.
00877     
00878     8/22/91 dmb: no longer attempt to attach structure to current outline.  used to 
00879     cause crash if an error occurred; cleaner to leave it to caller.
00880     */
00881     
00882     register hdlheadrecord h = nil;
00883     register short lastlevel = 0;
00884     register tydirection dir;
00885     Handle hlinetext;
00886     hdlheadrecord hnewnode;
00887     short level;
00888     boolean fl = false; /*guilty until proven innocent*/
00889     
00890     opstartinternalchange ();
00891     
00892     clearindentvalues (true);
00893     
00894     while (true) {
00895         
00896         if (!opgetlinetext (platform != thisplatform, packstream, &level, &hlinetext)) { /*consumed the text*/
00897             
00898             if (h != nil) /*success -- we got something*/
00899                 fl = true;
00900             
00901             break;
00902             }
00903         
00904         if (h == nil) { /*first line*/
00905             
00906             if (!opnewstructure (hlinetext, hnode))
00907                 break;
00908             
00909             h = *hnode;
00910             
00911             lastlevel = 0;
00912             }
00913         else {
00914             if (level > lastlevel) 
00915                 dir = right;
00916         
00917             else {
00918                 h = oprepeatedbump (left, lastlevel - level, h, true);
00919         
00920                 dir = down;
00921                 }
00922             
00923             if (!opdepositnewheadline (h, dir, hlinetext, &hnewnode)) {
00924                 
00925                 opdisposestructure (*hnode, false);
00926                 
00927                 break;
00928                 }
00929             
00930             h = hnewnode;
00931             
00932             lastlevel = level;
00933             }
00934         } /*while*/
00935     
00936     opendinternalchange ();
00937     
00938     return (fl);
00939     } /*opunpacktexttooutline*/
00940 
00941     
00942 static boolean opunpackversion2 (handlestream *packstream) {
00943     
00944     /*
00945     12/28/90 dmb: set hline1 according to vertcurrent -- used to be left at summit
00946     
00947     2/9/93 dmb: push/popstyle around texttooutline so that recalc isn't needed
00948     
00949     2.1b4 dmb: pushscratchport before measuring text
00950     
00951     3.0.4b8 dmb: use of scratchport is now more thorough
00952 
00953     5.0b11 dmb: added platform logic. map character if platform changes
00954     */
00955     
00956     register hdloutlinerecord ho;
00957     register long ixstart;
00958     handlestream stream;
00959     hdlheadrecord hsummit, hline1, hcursor;
00960     tyversion2diskheader header;
00961     short fontnum;
00962     long lnumcursor;
00963     boolean fl;
00964     
00965     ho = outlinedata; /*copy into register*/
00966     
00967     if (!readhandlestream (packstream, &header, sizeof (header)))
00968         return (false);
00969     
00970     (**ho).linespacing = conditionalenumswap (header.linespacing);
00971     
00972     (**ho).lineindent = conditionalshortswap (header.lineindent);
00973     
00974     (**ho).fltextmode = (boolean) conditionalshortswap (header.fltextmode);
00975     
00976     (**ho).vertscrollinfo.min = conditionalshortswap (header.vertmin);
00977     
00978     (**ho).vertscrollinfo.max = conditionalshortswap (header.vertmax);
00979     
00980     (**ho).vertscrollinfo.cur = diskwordstomemlong (header.vertcurrent, header.vertcurrent_hiword);
00981     
00982     (**ho).horizscrollinfo.min = conditionalshortswap (header.horizmin);
00983     
00984     (**ho).horizscrollinfo.max = conditionalshortswap (header.horizmax);
00985     
00986     (**ho).horizscrollinfo.cur = diskwordstomemlong (header.horizcurrent, header.horizcurrent_hiword);
00987     
00988     (**ho).timecreated = conditionallongswap (header.timecreated);
00989     
00990     (**ho).timelastsave = conditionallongswap (header.timelastsave);
00991     
00992     (**ho).ctsaves = conditionallongswap (header.ctsaves);
00993     
00994     disktomemshort (header.backcolor.red);
00995     disktomemshort (header.backcolor.green);
00996     disktomemshort (header.backcolor.blue);
00997     
00998     if (memcmp (&header.backcolor, &blackcolor, sizeof (RGBColor)) == 0)
00999         header.backcolor = whitecolor;
01000     
01001     // (**ho).backcolor = header.backcolor;
01002     
01003     diskgetfontnum (header.fontname, &fontnum);
01004     
01005     if (isemptystring (header.fontname)) //it was munged in beta
01006         (**ho).fontnum = config.defaultfont;
01007     else
01008         (**ho).fontnum = fontnum;
01009     
01010     if (header.fontsize == 0) //it was munged in beta
01011         (**ho).fontsize = config.defaultsize;
01012     else
01013         (**ho).fontsize = conditionalshortswap (header.fontsize);
01014     
01015     (**ho).fontstyle = conditionalshortswap (header.fontstyle);
01016     
01017     diskrecttorect (&header.windowrect, &(**ho).windowrect);
01018     
01019     disktomemlong (header.platform);
01020     
01021     disktomemlong (header.sizetext);
01022     
01023     disktomemlong (header.sizelinetable);
01024     
01025     if (header.platform == 0)
01026         header.platform = macplatform;
01027     
01028     if (header.outlinesignature == 0)
01029         header.outlinesignature = conditionallongswap ('LAND');
01030 
01031     (**ho).outlinesignature = conditionallongswap (header.outlinesignature);
01032     
01033     ixstart = (*packstream).pos;
01034     
01035     pushscratchport ();
01036     
01037     pushstyle ((**ho).fontnum, (**ho).fontsize, (**ho).fontstyle);
01038     
01039     stream = *packstream;
01040     
01041     stream.eof = stream.pos + header.sizetext;
01042     
01043     fl = opunpacktexttooutline (header.platform, &stream, &hsummit);
01044     
01045     popstyle ();
01046     
01047     popport ();
01048     
01049     if (!fl)
01050         return (false);
01051     
01052     (*packstream).pos += header.sizetext;
01053     
01054     stream = *packstream;
01055     
01056     stream.eof = stream.pos + header.sizelinetable;
01057     
01058     opsetsummit (ho, hsummit);
01059     
01060     opsetexpandedbits (hsummit, true); /*all 1st level items are expanded*/
01061     
01062     if (!optabletooutline (&stream, hsummit))
01063         return (false);
01064     
01065     (*packstream).pos += header.sizelinetable;
01066     
01067     hline1 = oprepeatedbump (flatdown, (**ho).vertscrollinfo.cur, hsummit, true);
01068     
01069     (**ho).hline1 = hline1;
01070     
01071     lnumcursor = diskwordstomemlong (header.lnumcursor, header.lnumcursor_hiword);
01072 
01073     hcursor = oprepeatedbump (flatdown, lnumcursor, hsummit, true);
01074     
01075     (**ho).hbarcursor = hcursor;
01076     
01077     opsetctexpanded (ho); /*don't bother saving this on disk, we re-compute*/
01078     
01079     return (true);
01080     } /*opunpackversion2*/
01081     
01082     
01083 boolean opunpack (Handle hpackedoutline, long *ixload, hdloutlinerecord *houtline) {
01084     
01085     /*
01086     9/25/91 dmb: added call to testheapspace to try to improve low-mem handling
01087     
01088     9/15/92 dmb: removed support for version1 format; it never shipped
01089     
01090     12/17/96 dmb: tolerate version numbers new than now, unless high byte changes
01091     */
01092     
01093     handlestream packstream;
01094     hdloutlinerecord ho;
01095     short versionnumber;
01096     boolean fl;
01097     
01098     *houtline = nil;
01099     
01100     if (!newoutlinerecord (&ho))
01101         return (false);
01102     
01103     openhandlestream (hpackedoutline, &packstream);
01104     
01105     packstream.pos = *ixload;
01106     
01107     if (!readhandlestream (&packstream, &versionnumber, sizeof (versionnumber))) {
01108     
01109         shellerrormessage (BIGSTRING ("\x3d" "Can't unpack outline because unexpected data was encountered."));
01110         
01111         opdisposeoutline (ho, false);
01112         
01113         return (false);
01114         }
01115     
01116     packstream.pos = *ixload;
01117     
01118     disktomemshort (versionnumber);
01119     
01120     oppushoutline (ho);
01121     
01122     switch (versionnumber) {
01123         
01124         case 2:
01125         case 3:
01126             fl = opunpackversion2 (&packstream);
01127             
01128             break;
01129         
01130         default:
01131             if ((hibyte (versionnumber) != hibyte (opversionnumber)) || versionnumber < 2) {
01132             
01133                 shellinternalerror (idbadopversionnumber, STR_bad_outline_version_number);
01134                 
01135                 fl = false;
01136                 }
01137             else
01138                 fl = opunpackversion2 (&packstream);
01139             
01140             break;
01141         
01142         } /*switch*/
01143     
01144     oppopoutline ();
01145     
01146     if (fl) { /*so far so good -- let's make sure we're not leaving memory dangerously low*/
01147         
01148         fl = testheapspace (0x800); /*2K gives us some room to play with*/
01149         }
01150     
01151     *ixload = packstream.pos;
01152     
01153     closehandlestream (&packstream);
01154     
01155     if (!fl) {
01156         
01157         opdisposeoutline (ho, false);
01158         
01159         return (false);
01160         }
01161     
01162     *houtline = ho;
01163     
01164     return (true);
01165     } /*opunpack*/
01166 
01167 
01168 boolean opunpackoutline (Handle hpackedoutline, hdloutlinerecord *houtline) {
01169     
01170     long ixload = 0;
01171     
01172     return (opunpack (hpackedoutline, &ixload, houtline));
01173     } /*opunpackoutline*/
01174 
01175 
01176 boolean optextscraptooutline (hdloutlinerecord houtline, Handle htext, hdlheadrecord *hnode) {
01177 #pragma unused (houtline)
01178 
01179     /*
01180     there seems to be an opportunity to factor code here.
01181     
01182     2.1b8 dmb: added houtline parameter to satisfy texttooutlinecallback 
01183     conventions. currently ignored here.
01184     
01185     5.0a4 dmb: added logic so empty lines don't dictate structure.
01186     */
01187     
01188     register hdlheadrecord hlast = nil;
01189     register short lastlevel = 0;
01190     tydirection dir;
01191     hdlheadrecord htree = nil;
01192     hdlheadrecord hnewnode;
01193     short level;
01194     Handle hlinetext;
01195     handlestream textstream;
01196     boolean fl = false; /*guilty until proven innocent*/
01197     
01198     opstartinternalchange ();
01199     
01200     openhandlestream (htext, &textstream);
01201     
01202     clearindentvalues (false);
01203     
01204     while (true) {
01205         
01206         if (!opgetlinetext (false, &textstream, &level, &hlinetext)) { /*no more text*/
01207             
01208             fl = true; /*success*/
01209             
01210             break;
01211             }
01212             
01213         if (hlast == nil) { /*first line*/
01214             
01215             if (!opnewstructure (hlinetext, &htree))
01216                 break;
01217             
01218             hlast = htree;
01219             
01220             lastlevel = 0;
01221             
01222             continue; /*finished with this one*/
01223             }
01224         
01225          /* 2005-01-21 creedon, aradke, JES - empty lines DO dictate structure < http://sourceforge.net/tracker/index.php?func=detail&aid=1093595&group_id=120666&atid=687798 > */
01226          /* if (gethandlesize (hlinetext) == 0) // 5.0a4 dmb: empty lines don't dictate structure
01227             level = lastlevel; */
01228         
01229         if (level > lastlevel) {
01230             
01231             dir = right;
01232             }
01233         else { /*surface 0 or more times*/
01234         
01235             hlast = oprepeatedbump (left, lastlevel - level, hlast, true);
01236     
01237             dir = down;
01238             }
01239         
01240         if (!opdepositnewheadline (hlast, dir, hlinetext, &hnewnode))
01241             break;
01242         
01243         hlast = hnewnode;
01244         
01245         lastlevel = level;
01246         } /*while*/
01247     
01248     closehandlestream (&textstream);
01249     
01250     opendinternalchange ();
01251     
01252     if (!fl) { /*didn't succeed -- toss accumulated structure and return false*/
01253         
01254         if (htree != nil)
01255             opdisposestructure (htree, false);
01256         
01257         return (false);
01258         }
01259     
01260     *hnode = htree;
01261     
01262     return (htree != nil);
01263     } /*optextscraptooutline*/
01264 
01265 
01266 static short outscraplevel = 0; /*for communications while sending to scrap*/
01267 
01268 
01269 static boolean outscrapvisit (hdlheadrecord hnode, ptrvoid refcon) {
01270     
01271     /*
01272     6/12/91 dmb: validate outlinedata.  currently, menubar scraps will only 
01273     export properly while a menubar outline is active.  the problem is that 
01274     the scrap is a standalone headline; it needs to have an outline record too.
01275     */
01276     
01277     register hdlheadrecord h = hnode;
01278     ptroppackinfo packinfo = (ptroppackinfo) refcon;
01279     handlestream *s;
01280     
01281     if (!outtextvisit (h, packinfo))
01282         return (false);
01283     
01284     if ((**h).hrefcon != nil) {
01285         
01286         assert (outlinedata != nil);
01287         
01288         if (outlinedata == nil)
01289             return (false);
01290         
01291         s = (*packinfo).packstream;
01292         
01293         closehandlestream (s);
01294         
01295         if (!(*(**outlinedata).textualizerefconcallback) (h, (*s).data))
01296             return (false);
01297         
01298         openhandlestream ((*s).data, s);
01299         
01300         (*s).pos = (*s).eof;
01301         }
01302     
01303     return (true);
01304     } /*outscrapvisit*/
01305 
01306 
01307 boolean opoutlinetotextstream (hdloutlinerecord houtline, boolean flomitcomments, handlestream *s) {
01308     
01309     /*
01310     convert the outline into a block of tab-indented text, each
01311     line ended by a carriage return.  suitable for passing through 
01312     the clipboard to a text-based application.
01313     */
01314     
01315     tyoppackinfo packinfo;
01316     boolean fl;
01317     
01318     outscraplevel = 0;
01319     
01320     packinfo.packstream = s;
01321     
01322     packinfo.flpackcomments = !flomitcomments;
01323     
01324     oppushoutline (houtline);
01325     
01326     opwriteeditbuffer (); /*if a headline is being edited, update text handle*/
01327     
01328     fl = opsiblingvisiter ((**houtline).hsummit, false, &outscrapvisit, &packinfo);
01329     
01330     oppopoutline ();
01331     
01332     return (fl);
01333     } /*opoutlinetotextstream*/
01334 
01335 
01336 boolean opoutlinetotextscrap (hdloutlinerecord houtline, boolean flomitcomments, Handle htext) {
01337     
01338     /*
01339     stick the handle into a handlestream and pass it on through...
01340     */
01341     
01342     handlestream packstream;
01343     boolean fl;
01344     
01345     openhandlestream (htext, &packstream);
01346     
01347     fl = opoutlinetotextstream (houtline, flomitcomments, &packstream);
01348     
01349     closehandlestream (&packstream);
01350     
01351     return (fl);
01352     } /*opoutlinetotextscrap*/
01353 
01354 
01355 boolean opoutlinetonewtextscrap (hdloutlinerecord houtline, Handle *htext) {
01356     
01357     /*
01358     similar to opoutlinetotextscrap above, but allocated new handle
01359     */
01360     
01361     if (!newgrowinghandle (0, htext))
01362         return (false);
01363     
01364     if (opoutlinetotextscrap (houtline, false, *htext))
01365         return (true);
01366     
01367     disposehandle (*htext);
01368     
01369     *htext = nil;
01370     
01371     return (false);
01372     } /*opoutlinetonewtextscrap*/
01373 
01374 
01375 /*
01376 boolean opsuboutlinetonewtextscrap (hdlheadrecord hnode, Handle *htext) {
01377     
01378     /%
01379     similar to opoutlinetotextscrap above, but allocated new handle and 
01380     only visits hnode and its subheads
01381     %/
01382     
01383     register hdlheadrecord h = hnode;
01384     
01385     if (!newemptyhandle (htext))
01386         return (false);
01387     
01388     outscraplevel = 0;
01389     
01390     packhandle = *htext;
01391     
01392     if (outscrapvisit (h) && oprecursivelyvisit (h, infinity, &outscrapvisit))
01393         return  (true);
01394     
01395     disposehandle (*htext);
01396     
01397     return (false);
01398     } /%opsuboutlinetonewtextscrap%/
01399 */
01400 
01401 

Generated on Wed May 31 18:19:57 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6