Fl_Help_View.cxx 214 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381
  1. //
  2. // "$Id: Fl_Help_View.cxx 9325 2012-04-05 05:12:30Z fabien $"
  3. //
  4. // Fl_Help_View widget routines.
  5. //
  6. // Copyright 1997-2010 by Easy Software Products.
  7. // Image support by Matthias Melcher, Copyright 2000-2009.
  8. //
  9. // This library is free software. Distribution and use rights are outlined in
  10. // the file "COPYING" which should have been included with this file. If this
  11. // file is missing or damaged, see the license at:
  12. //
  13. // http://www.fltk.org/COPYING.php
  14. //
  15. // Please report all bugs and problems on the following page:
  16. //
  17. // http://www.fltk.org/str.php
  18. //
  19. // Contents:
  20. //
  21. // Fl_Help_View::Fl_Help_View() - Build a Fl_Help_View widget.
  22. // Fl_Help_View::add_block() - Add a text block to the list.
  23. // Fl_Help_View::add_link() - Add a new link to the list.
  24. // Fl_Help_View::add_target() - Add a new target to the list.
  25. // Fl_Help_View::begin_selection() - Begin text selection.
  26. // Fl_Help_View::build_faces() - build font face look-up tables.
  27. // Fl_Help_View::clear_global_selection() - Clear text selection.
  28. // Fl_Help_View::clear_selection() - Clear current text selection.
  29. // Fl_Help_View::cmp_targets() - Compare two targets.
  30. // Fl_Help_View::do_align() - Compute alignment for a line in a block.
  31. // Fl_Help_View::draw() - Draw the Fl_Help_View widget.
  32. // Fl_Help_View::end_selection() - End text selection.
  33. // Fl_Help_View::extend_selection()- Extend current text selection.
  34. // Fl_Help_View::fileislink() - Was link clicked or nav button?
  35. // Fl_Help_View::filepath() - Set value file path string.
  36. // Fl_Help_View::filepath() - Get value file path string.
  37. // Fl_Help_View::find() - Find the specified string.
  38. // Fl_Help_View::find_link() - Find the link at the given position.
  39. // Fl_Help_View::follow_link() - Follow the specified link.
  40. // Fl_Help_View::font_face() - Get a font face from a list of names.
  41. // Fl_Help_View::font_style() - Get a font style from a font list index.
  42. // Fl_Help_View::format() - Format the help text.
  43. // Fl_Help_View::format_table() - Format a table.
  44. // Fl_Help_View::free_data() - Free memory used for the document.
  45. // Fl_Help_View::get_align() - Get an alignment attribute.
  46. // Fl_Help_View::get_attr() - Get an attribute value from the string.
  47. // Fl_Help_View::get_color() - Get an alignment attribute.
  48. // Fl_Help_View::get_css_value() - Outputs the value of a given css property to buffer.
  49. // Fl_Help_View::get_font_size() - Get a height value for font-size.
  50. // Fl_Help_View::get_image() - Get an inline image.
  51. // Fl_Help_View::get_length() - Get a length value either absolute or %.
  52. // Fl_Help_View::get_length() - Get a length value of a given width.
  53. // Fl_Help_View::gettopline() - Get current topline in document.
  54. // Fl_Help_View::handle() - Handle events in the widget.
  55. // Fl_Help_View::hv_draw() - Draws text.
  56. // Fl_Help_View::initfont() - Initialize font stack.
  57. // Fl_Help_View::leftline() - Set the left line position.
  58. // Fl_Help_View::load() - Load the specified file.
  59. // Fl_Help_View::load_css() - Loads a css file.
  60. // Fl_Help_View::parse_css() - Parses all supported css properties.
  61. // Fl_Help_View::popfont() - Pop from font stack.
  62. // Fl_Help_View::pushfont() - Push to font stack.
  63. // Fl_Help_View::resize() - Resize the help widget.
  64. // Fl_Help_View::select_all() - Select all text.
  65. // Fl_Help_View::setstyle() - - Set the html style flag.
  66. // Fl_Help_View::topline() - Set the top line to the named target.
  67. // Fl_Help_View::topline() - Set the top line by number.
  68. // Fl_Help_View::value() - Set the help text directly.
  69. // Fl_Help_View::~Fl_Help_View() - Destroy a Fl_Help_View widget.
  70. //
  71. // Local:
  72. //
  73. // command() - Convert a command with up to four letters into an uint.
  74. // quote_char() - Return the character code associated with a quoted char.
  75. // hscrollbar_callback() - Callback for the horizontal scrollbar.
  76. // scrollbar_callback() - Callback for the scrollbar.
  77. //
  78. /*
  79. markcw: since July 2008 I have heavily modified this file and it's
  80. header. To make it a little easier for me to follow I made original
  81. code comments start in uppercase and my code comments start in lowercase.
  82. List of currently supported HTML tags/elements with attributes:
  83. <a href name target></a>
  84. <b></b> <strong></strong>
  85. <blockquote type></blockquote>
  86. <dl compact></dl> <dd> <dt>
  87. <ol type></ol> <li type></li>
  88. <ul type></ul> <li type></li>
  89. <body background bgcolor text link vlink alink></body>
  90. <br clear>
  91. <center></center>
  92. <code></code> <tt></tt>
  93. <div align id></div>
  94. <font face size color></font>
  95. <h1 align></h1>
  96. <head></head>
  97. <hr width size align clear>
  98. <html></html>
  99. <i></i> <em></em>
  100. <img src lowsrc alt align width height hspace vspace border usemap name>
  101. <kbd></kbd>
  102. <noscript></noscript>
  103. <p align></p>
  104. <pre></pre>
  105. <script language src></script>
  106. <table bgcolor background border cellpadding cellspacing width height></tab>
  107. <tr valign align bgcolor background></tr>
  108. <td valign align width height colspan rowspan bgcolor background></td>
  109. <th as td></th>
  110. <title></title>
  111. <u></u>
  112. <var></var>
  113. */
  114. //
  115. // Include necessary header files
  116. //
  117. #include <FL/Fl_Help_View.H>
  118. #include <FL/Fl_Window.H>
  119. #include <FL/Fl_Pixmap.H>
  120. #include <FL/x.H>
  121. #include <stdio.h>
  122. #include <stdlib.h>
  123. #include "flstring.h"
  124. #include <ctype.h>
  125. #include <errno.h>
  126. #include <math.h>
  127. #include "forms_timer.cxx" // for fl_gettime in resize()
  128. #if defined(WIN32) && ! defined(__CYGWIN__)
  129. # include <io.h>
  130. # include <direct.h>
  131. // Visual C++ 2005 incorrectly displays a warning about the use of
  132. // POSIX APIs on Windows, which is supposed to be POSIX compliant...
  133. # define getcwd _getcwd
  134. #else
  135. # include <unistd.h>
  136. #endif // WIN32
  137. //
  138. // Define preprocessor constants and macros
  139. //
  140. #define HV_64 64 // Columns, was 200 but practically 64 is enough
  141. #define HV_32 32 // medium array size
  142. #define HV_16 16 // small array size
  143. #define HV_DEFAULT 0 // html style flag
  144. #define HV_NOCONTEXTMENU 1 // no right-click menu
  145. #define HV_NONAVIGATE 2 // no user navigation
  146. // 'ENC(ANSI/Unicode, Mac Roman)' - OS character encoding macro
  147. #ifdef ENC
  148. # undef ENC
  149. #endif
  150. #ifdef __APPLE__
  151. # define ENC(a, b) b
  152. #else
  153. # define ENC(a, b) a
  154. #endif
  155. // 'CTRL(char)' - Shortcut key macro, get bits 0..4 of char
  156. #define CTRL(x) ((x) & 0x1f)
  157. // 'CMD(char[0], char[1], char[2], char[3])' - Fourcc macro, chars to int
  158. #define CMD(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d)
  159. // 'CHR(int, charindex)' - char from int macro, used like a 4-char array
  160. #define CHR(a, b) ((a & (255 << ((3-(b & 3)) << 3))) >> ((3-(b & 3)) << 3))
  161. // 'MIL(sec, mil, sec2, mil2)' - difference in mil macro, using fl_gettime
  162. #define MIL(a, b, c, d) ((c > a || (c == a && d > b)) ? \
  163. (1000000 * (c - a)) - b + d : \
  164. (1000000 * (a - c)) - d + b)
  165. //
  166. // Typedef the C API sort function type the only way I know how...
  167. //
  168. extern "C" // Compile qsort() in C style to avoid any compiler errors
  169. {
  170. typedef int (*compare_func_t)(const void *, const void *);
  171. }
  172. //
  173. // Declare local functions
  174. //
  175. static unsigned int command(const char *cmdp); // Used in end_selection
  176. static int quote_char(const char *qp, int fc = 0); // added fc
  177. static void hscrollbar_callback(Fl_Widget *s, void *);
  178. static void scrollbar_callback(Fl_Widget *s, void *);
  179. //
  180. // Broken image
  181. //
  182. static const char *broken_xpm[] =
  183. {
  184. "16 24 4 1",
  185. "@ c #000000", // Black
  186. " c #ffffff", // White
  187. "+ c none", // Transparent
  188. "x c #ff0000", // Red
  189. // Pixels
  190. "@@@@@@@+++++++++",
  191. "@ @++++++++++",
  192. "@ @+++++++++++",
  193. "@ @++@++++++++",
  194. "@ @@+++++++++",
  195. "@ @+++@+++++",
  196. "@ @++@@++++@",
  197. "@ xxx @@ @++@@",
  198. "@ xxx xx@@ @",
  199. "@ xxx xxx @",
  200. "@ xxxxxx @",
  201. "@ xxxx @",
  202. "@ xxxxxx @",
  203. "@ xxx xxx @",
  204. "@ xxx xxx @",
  205. "@ xxx xxx @",
  206. "@ @",
  207. "@ @",
  208. "@ @",
  209. "@ @",
  210. "@ @",
  211. "@ @",
  212. "@ @",
  213. "@@@@@@@@@@@@@@@@",
  214. 0 // nul-terminate - rem'd NULL
  215. };
  216. static Fl_Pixmap broken_image(broken_xpm);
  217. //
  218. // Simple margin stack for Fl_Help_View::format()
  219. //
  220. struct fl_margins
  221. {
  222. int depth_; // Array index
  223. int default_margin_;
  224. int margins_[100]; // Margins stack
  225. fl_margins(int default_margin=10) {
  226. default_margin_ = default_margin;
  227. clear();
  228. }
  229. int clear() { // Init margins
  230. // puts("fl_margins::clear()");
  231. depth_ = 0;
  232. return margins_[0] = default_margin_; // Default indent
  233. }
  234. int current() { // Get current margin
  235. return margins_[depth_];
  236. }
  237. int pop() { // Get last margin
  238. //printf("fl_margins::pop(): depth_=%d, xx=%d\n", depth_,
  239. // (depth_ > 0) ? margins_[depth_ - 1] : 4);
  240. if (depth_ > 0) {
  241. depth_ --;
  242. return margins_[depth_];
  243. }
  244. else
  245. return default_margin_; // Default indent
  246. }
  247. int push(int indent) { // Set next margin
  248. int xx;
  249. xx = margins_[depth_] + indent; // New indent
  250. //printf("fl_margins::push(indent=%d): depth_=%d, xx=%d\n", indent,
  251. // depth_ + 1, xx);
  252. if (depth_ < 99) {
  253. depth_ ++;
  254. margins_[depth_] = xx;
  255. }
  256. return xx;
  257. }
  258. };
  259. //
  260. // All the stuff needed to implement text selection in Fl_Help_View
  261. //
  262. /* matt:
  263. We are trying to keep binary compatibility with previous versions
  264. of FLTK. This means that we are limited to adding static data members
  265. only to not enlarge the Fl_Help_View class. Lucky for us, only one
  266. text can be selected system wide, so we can remember the selection
  267. in a single set of values.
  268. Still to do:
  269. - &word; style characters mess up our count inside a word boundary
  270. - we can only select words, no individual characters
  271. - no dragging of the selection into another widget
  272. - selection must be cleared if another widget get focus!
  273. - write a comment for every new function
  274. markcw: Static data members don't change the binary size or layout
  275. of a class because they are defined externally.
  276. For more info on binary compatibility (BC) see:
  277. http://techbase.kde.org/Policies/Binary_Compatibility_Issues_With_C++
  278. */
  279. /*
  280. matt: The following functions are also used to draw stuff and should be
  281. replaced with local copies that are much faster when merely counting.
  282. fl_color(Fl_Color);
  283. fl_rectf(int, int, int, int);
  284. fl_push_clip(int, int, int, int);
  285. fl_xyline(int, int, int);
  286. fl_rect()
  287. fl_line()
  288. img->draw()
  289. markcw: local functions more-so static are faster than class functions.
  290. */
  291. //
  292. // Fl_Help_View::Fl_Help_View() - Build a Fl_Help_View widget.
  293. //
  294. Fl_Help_View::Fl_Help_View(int xx, // I - Left position
  295. int yy, // I - Top position
  296. int ww, // I - Width in pixels
  297. int hh, // I - Height in pixels
  298. const char *lp) // I - Label pointer, opt
  299. : Fl_Group(xx, yy, ww, hh, lp),
  300. scrollbar_(xx + ww - Fl::scrollbar_size(), yy,
  301. Fl::scrollbar_size(), hh - Fl::scrollbar_size()),
  302. hscrollbar_(xx, yy + hh - Fl::scrollbar_size(),
  303. ww - Fl::scrollbar_size(), Fl::scrollbar_size())
  304. {
  305. color(FL_WHITE, FL_SELECTION_COLOR); // Set bgcolor and selcolor of widget - rem'd FL_BACKGROUND2_COLOR
  306. title_[0] = '\0'; // Title string
  307. defcolor_ = FL_BLACK; // Default text color - rem'd FL_FOREGROUND_COLOR
  308. bgcolor_ = FL_WHITE; // Background color - rem'd FL_BACKGROUND_COLOR
  309. textcolor_ = defcolor_; // Text color
  310. linkcolor_ = FL_BLUE; // Link color - rem'd FL_SELECTION_COLOR
  311. serifont_ = FL_TIMES; // Default font, was textfont_
  312. fontsize_ = 12; // Default font size, was textsize_
  313. value_ = 0; // HTML text value - rem'd NULL
  314. ablocks_ = 0; // Allocated blocks
  315. nblocks_ = 0; // Number of blocks
  316. blocks_ = (Fl_Help_Block *)0; // Blocks
  317. link_ = (Fl_Help_Func *)0; // Link transform function
  318. alinks_ = 0; // Allocated links
  319. nlinks_ = 0; // Number of links
  320. links_ = (Fl_Help_Link *)0; // Links
  321. //targets_ = (Fl_Help_Target *)0; // rem'd
  322. atargets_ = 0; // Allocated targets
  323. ntargets_ = 0; // Number of targets
  324. directory_[0] = '\0'; // Directory for current file
  325. filename_[0] = '\0'; // Current filename
  326. topline_ = 0; // Top line in document
  327. leftline_ = 0; // Lefthand position
  328. size_ = 0; // Total document length
  329. hsize_ = 0; // Maximum document width
  330. scrollbar_size_ = 0;
  331. scrollbar_.value(0, hh, 0, 1);
  332. scrollbar_.step(8.0);
  333. scrollbar_.show();
  334. scrollbar_.callback(scrollbar_callback);
  335. scrollbar_.linesize(32); // vertical scroll size, default is 16
  336. hscrollbar_.value(0, ww, 0, 1); // Set line position, window, top, total
  337. hscrollbar_.step(8.0); // Set mouse step rounding value
  338. hscrollbar_.show(); // Show widget
  339. hscrollbar_.callback(hscrollbar_callback); // Set callback func for widget
  340. hscrollbar_.type(FL_HORIZONTAL); // Set slider type, default is vertical
  341. end(); // End current Fl_Group widgets
  342. selection_first = 0;
  343. selection_last = 0;
  344. selection_push_first = 0;
  345. selection_push_last = 0;
  346. selection_drag_first = 0;
  347. selection_drag_last = 0;
  348. selected = 0;
  349. draw_mode = 0;
  350. mouse_x = 0;
  351. mouse_y = 0;
  352. current_pos = 0;
  353. current_view = 0; // rem'd NULL
  354. hv_selection_color = 0;
  355. hv_selection_text_color = 0;
  356. default_margin_ = 10; //internall padding
  357. tr_td_adjust_ = 0; //when printint with pdfs
  358. d = (Fl_Help_Target *)malloc(sizeof(Fl_Help_Target)); // d-pointer
  359. d->targets = (Fl_Help_Link *)0; // Targets
  360. d->linkp = (Fl_Help_Link *)0; // Currently clicked link
  361. d->ispush = 0; // link is pushed
  362. d->islink = 0; // link clicked
  363. d->resized = 0; // window resized
  364. d->ispath = 0; // is path used
  365. d->nstyle = 0; // navigation style flag
  366. d->isnew = 0; // is new page
  367. d->top = 0; // current topline
  368. d->ltop = 0; // last topline
  369. d->isnav = 0; // is nav link
  370. d->rwidth = w(); // resize width
  371. d->cssurllen = 0; // css url length
  372. d->csswordlen = 0; // css word length
  373. d->cssword = 0; // css word value
  374. d->rtime = 0; // resize time
  375. d->rsec = 0; // resize seconds
  376. d->rmil = 0; // resize millisecs
  377. d->csstextlen = 0; // css text length
  378. d->csstext = 0; // css text value
  379. d->cssurl = 0; // css url value
  380. d->path[0] = '\0'; // current file path
  381. d->lpath[0] = '\0'; // last file path
  382. d->fonts[0][0] = 0; // font stack
  383. d->nfonts = 0; // number of fonts in stack
  384. build_faces();
  385. // load new default fonts
  386. serifont_ = FL_TIMES; // default/serif font
  387. sansfont_ = FL_HELVETICA; // sans font
  388. monofont_ = FL_COURIER; // monospace font
  389. resize(xx, yy, ww, hh); // Resize widget
  390. } // Fl_Help_View::Fl_Help_View()
  391. //
  392. // Fl_Help_View::add_block() - replaced, code moved
  393. //
  394. Fl_Help_Block * // O - Pointer to new block
  395. Fl_Help_View::add_block(const char *sp, // I - Pointer to start
  396. int xx, // I - X position
  397. int yy, // I - Y position
  398. int ww, // I - Right margin
  399. int hh, // I - Height
  400. unsigned char bc) // I - Draw border, opt
  401. {
  402. return 0;
  403. } // Fl_Help_View::add_block()
  404. //
  405. // Fl_Help_View::add_block() - Add a text block to the list.
  406. //
  407. Fl_Help_Block * // O - Pointer to new block
  408. Fl_Help_View::add_block(const Fl_Help_Block &b, // I - block object
  409. const char *sp, // I - Pointer to start
  410. int ww) // I - Right margin
  411. {
  412. Fl_Help_Block *block; // New block
  413. if (nblocks_ >= ablocks_) {
  414. ablocks_ += 16; // Allocated blocks, 16 blocks per allocation
  415. int size = sizeof(Fl_Help_Block) * ablocks_; // block size
  416. if (ablocks_ == 16) // Memory was freed
  417. blocks_ = (Fl_Help_Block *)malloc(size);
  418. else // First pass or resize resulted in a few new blocks
  419. blocks_ = (Fl_Help_Block *)realloc(blocks_, size);
  420. }
  421. block = blocks_ + nblocks_;
  422. memset(block, 0, sizeof(Fl_Help_Block));
  423. block->start = sp; // Start of text, varies so set by sp
  424. block->end = sp; // End of text, varies so set by sp
  425. block->x = b.x; // Starting X coordinate
  426. block->y = b.y; // Starting Y coordinate
  427. block->w = ww; // Width, varies so set by ww
  428. block->h = 0; // Height, always zero
  429. block->maxh = 0; // max image height
  430. block->imgy = 0; // image y position
  431. block->pre = b.pre; // pre text flag
  432. block->tag = b.tag; // tag/element fourcc int
  433. block->border = b.border; // Draw border?
  434. block->border_color = b.border_color; // Border color
  435. block->font = b.font; // current font
  436. block->fsize = b.fsize; // current font size
  437. block->bgcolor = b.bgcolor; // Background color
  438. block->cbi = nblocks_; // current block index
  439. nblocks_ ++; // Number of blocks
  440. return block;
  441. } // Fl_Help_View::add_block()
  442. //
  443. // Fl_Help_View::add_link() - Add a new link to the list.
  444. //
  445. void Fl_Help_View::add_link(const char *np, // I - Name of link
  446. int xx, // I - X position of link
  447. int yy, // I - Y position of link
  448. int ww, // I - Width of link text
  449. int hh) // I - Height of link text
  450. {
  451. Fl_Help_Link *link; // New link
  452. char *target; // Pointer to target name
  453. if (nlinks_ >= alinks_) {
  454. alinks_ += 16; // Allocated links, 16 blocks per allocation
  455. int size = sizeof(Fl_Help_Link) * alinks_; // block size
  456. if (alinks_ == 16)
  457. links_ = (Fl_Help_Link *)malloc(size);
  458. else
  459. links_ = (Fl_Help_Link *)realloc(links_, size);
  460. }
  461. link = links_ + nlinks_;
  462. link->x = xx; // X offset of link text
  463. link->y = yy; // Y offset of link text
  464. link->w = xx + ww; // Width of link text
  465. link->h = yy + hh; // Height of link text
  466. strlcpy(link->filename, np, sizeof(link->filename)); // nul-terminated
  467. if ((target = strrchr(link->filename, '#'))) { // Last '#' - rem'd != 0
  468. *(target ++) = '\0'; // Remove target from link->filename
  469. strlcpy(link->name, target, sizeof(link->name)); // Link target
  470. }
  471. else
  472. link->name[0] = '\0'; // Blank link target
  473. nlinks_ ++; // Number of links
  474. } // Fl_Help_View::add_link()
  475. //
  476. // Fl_Help_View::add_target() - Add a new target to the list.
  477. //
  478. void Fl_Help_View::add_target(const char *np, // I - Name of target
  479. int yy) // I - Y position of target
  480. {
  481. Fl_Help_Link *target; // New target
  482. if (ntargets_ >= atargets_) {
  483. atargets_ += 16; // Allocated targets, 16 blocks per allocation
  484. int size = sizeof(Fl_Help_Link) * atargets_; // block size
  485. if (atargets_ == 16)
  486. d->targets = (Fl_Help_Link *)malloc(size);
  487. else
  488. d->targets = (Fl_Help_Link *)realloc(d->targets, size);
  489. }
  490. target = d->targets + ntargets_;
  491. target->y = yy; // Y offset
  492. strlcpy(target->name, np, sizeof(target->name)); // Target name
  493. ntargets_ ++; // Number of targets
  494. } // Fl_Help_View::add_target()
  495. //
  496. // Fl_Help_View::begin_selection() - Begin text selection.
  497. //
  498. char // O - True if text selected
  499. Fl_Help_View::begin_selection()
  500. {
  501. clear_global_selection();
  502. if (!Fl_Help_View_buffer)
  503. Fl_Help_View_buffer = fl_create_offscreen(1, 1);
  504. mouse_x = Fl::event_x();
  505. mouse_y = Fl::event_y();
  506. draw_mode = 1; // Begin selection mode
  507. current_view = this;
  508. fl_begin_offscreen(Fl_Help_View_buffer);
  509. draw();
  510. fl_end_offscreen();
  511. draw_mode = 0;
  512. if (selection_push_last)
  513. return 1;
  514. else
  515. return 0;
  516. } // Fl_Help_View::begin_selection()
  517. //
  518. // Fl_Help_View::build_faces() - build font face look-up tables.
  519. //
  520. unsigned char // O - number of font faces
  521. Fl_Help_View::build_faces()
  522. {
  523. char buf[100],
  524. namebuf[100],
  525. tbufs[100][100]; // buffers
  526. const char *namep; // pointer
  527. char *bufp,
  528. *namebufp; // r+w pointer
  529. int ti = 0,
  530. tj = 0,
  531. tk = 0, // temp loop vars
  532. tnum = 0,
  533. lnum = 0,
  534. fnum = 0, // temp/last/font counters
  535. tfi[100],
  536. tf[10],
  537. cbit = 0,
  538. fbit = 0,
  539. tbit = 0, // bits
  540. nfonts = 0,
  541. nfaces = 0, // number of fonts and faces
  542. temp = 0; // lengths
  543. strlcpy(buf, " ", sizeof(buf)); // init buffer
  544. memset(face_, 0, sizeof(face_)); // zero tables
  545. memset(flet_, 0, sizeof(flet_));
  546. memset(fref_, 0, sizeof(fref_));
  547. nfonts = Fl::set_fonts(0); // number of ISO8859-1 fonts in list
  548. for (ti = 0, nfaces = 0; ti < nfonts; ti ++) { // find base fonts
  549. namep = Fl::get_font_name((Fl_Font)ti, &temp); // fltk font name
  550. for (tk = 0; namep[tk] != '\0'; tk ++)
  551. namebuf[tk] = tolower(namep[tk]); // copy chars to lowercase
  552. namebuf[tk] = '\0'; // nul-terminate
  553. if (strstr(namebuf+1, "black") || strstr(namebuf+1, "bold") ||
  554. strstr(namebuf+1, "extra") || strstr(namebuf+1, "heavy") ||
  555. strstr(namebuf+1, "inclined") || strstr(namebuf+1, "italic") ||
  556. strstr(namebuf+1, "light") || strstr(namebuf+1, "oblique") ||
  557. strstr(namebuf+1, "slanted") || strstr(namebuf+1, "wide") ||
  558. strstr(namebuf+1, "ultra"))
  559. continue; // skip font styles
  560. if ((bufp = strstr(namebuf, "-"))) { // full font name
  561. if (strstr(bufp+1, "bd") || strstr(bufp+1, "cond") ||
  562. strstr(bufp+1, "cn") || strstr(bufp+1, "it") ||
  563. strstr(bufp+1, "obl") || strstr(bufp+1, "smbd"))
  564. continue; // skip font styles
  565. }
  566. temp = strlen(namebuf);
  567. if (temp < (int)strlen(buf)) temp = strlen(buf); // use bigger length
  568. if (!strncmp(namebuf, buf, temp)) continue; // same name as last
  569. if (nfaces < (int)sizeof(face_)/8) { // store next face
  570. face_[nfaces][2] = ti; // first font for face
  571. face_[nfaces][3] = (uchar)*namebuf; // first letter for face, a..z
  572. if (face_[nfaces][3] < 97 || face_[nfaces][3] > 123)
  573. face_[nfaces][3] = 123; // illegal char, z
  574. nfaces ++; // next face
  575. }
  576. strlcpy(buf, namebuf, sizeof(buf)); // last name in buffer
  577. }
  578. for (ti = 0, fnum = 0; ti < 27; ti ++) { // sort faces alphabetically
  579. for (tj = 0; tj < nfaces; tj ++) {
  580. tnum = face_[tj][3] - 97; // first letter, a = 0
  581. if (ti == tnum) { // current letter match
  582. face_[fnum][0] = face_[tj][2]; // first font index
  583. face_[fnum][1] = face_[tj][3]; // first letter
  584. fnum ++; // next face
  585. }
  586. }
  587. }
  588. for (ti = 0; ti < nfaces; ti ++) { // store all fonts in face table
  589. fnum = face_[ti][0]; // face index
  590. namep = Fl::get_font_name((Fl_Font)fnum, &temp);
  591. for (tk = 0; namep[tk] != '\0'; tk ++)
  592. buf[tk] = tolower(namep[tk]);
  593. buf[tk] = '\0'; // nul-terminate
  594. if (!(bufp = strstr(buf, "-"))) bufp = buf + tk;
  595. *bufp = '\0'; // shorten full name
  596. strlcpy(tbufs[0], buf, sizeof(tbufs[0]));
  597. face_[ti][1] = face_[ti][2] = face_[ti][3] = 0; // reset
  598. memset(tf, 0, sizeof(tf));
  599. for (tj = 0, tfi[0] = fnum, lnum = 1; tj < nfonts; tj ++) { // get all fonts of face
  600. namep = Fl::get_font_name((Fl_Font)tj, &temp); // fltk font name
  601. for (tk = 0; namep[tk] != '\0'; tk ++)
  602. namebuf[tk] = tolower(namep[tk]); // copy to lowercase
  603. namebuf[tk] = '\0'; // nul-terminate
  604. if (!isalpha(namebuf[0])) continue; // skip foreign chars
  605. if (!(namebufp = strstr(namebuf, "-"))) namebufp = namebuf; // full font name
  606. if (strstr(namebuf, " ") && namebufp == namebuf) { // basic font name
  607. namebufp = strstr(namebuf, " bold");
  608. if (!namebufp) namebufp = strstr(namebuf, " italic");
  609. if (!namebufp) namebufp = strstr(namebuf, " oblique");
  610. }
  611. if (!strncmp(buf, namebuf, bufp-buf) && (namebufp-namebuf == bufp-buf)) { // face name match
  612. strlcpy(tbufs[lnum], namebuf, sizeof(tbufs[lnum]));
  613. tfi[lnum] = tj; // font indexes
  614. lnum ++; // count fonts
  615. if (strstr(namebuf, "-")) { // abbreviations if full name
  616. if (strstr(namebufp+1, "bd")) tf[1] = 1;
  617. if (strstr(namebufp+1, "it")) tf[2] = 1;
  618. }
  619. if (strstr(namebufp+1, "bold")) tf[1] = 1; // set flags of current face
  620. if (strstr(namebufp+1, "italic")) tf[2] = 1;
  621. if (strstr(namebufp+1, "medium")) tf[3] = 1;
  622. if (strstr(namebufp+1, "plain")) tf[4] = 1;
  623. if (strstr(namebufp+1, "regular")) tf[5] = 1;
  624. }
  625. }
  626. for (tj = 0; tj < lnum; tj ++, tk = 0) { // sort fonts styles in face
  627. if (!(namebufp = strstr(tbufs[tj], "-"))) namebufp = tbufs[tj];
  628. if (tf[1] && strstr(namebufp+1, "black")) tk = 1; // favour bold, italic, etc
  629. else if (strstr(namebufp+1, "condensed")) tk = 1;
  630. else if (strstr(namebufp+1, "cond") && namebufp > tbufs[tj]) tk = 1;
  631. else if (strstr(namebufp+1, "cn") && namebufp > tbufs[tj]) tk = 1;
  632. else if (strstr(namebufp+1, "extra")) tk = 1;
  633. else if (tf[1] && strstr(namebufp+1, "heavy")) tk = 1;
  634. else if ((tf[3] || tf[4] || tf[5]) && strstr(namebufp+1, "light")) tk = 1;
  635. else if (tf[2] && strstr(namebufp+1, "light")) tk = 1;
  636. else if (tf[2] && strstr(namebufp+1, "oblique")) tk = 1;
  637. else if (tf[2] && strstr(namebufp+1, "obl") && namebufp > tbufs[tj]) tk = 1;
  638. else if (tf[2] && strstr(namebufp+1, "inclined")) tk = 1;
  639. else if (tf[1] && strstr(namebufp+1, "semibold")) tk = 1;
  640. else if (tf[1] && strstr(namebufp+1, "smbd") && namebufp > tbufs[tj]) tk = 1;
  641. else if (tf[2] && strstr(namebufp+1, "slanted")) tk = 1;
  642. else if (strstr(namebufp+1, "ultra")) tk = 1;
  643. if (lnum > 8 && tf[1] && tf[2]) { // simplify if too many variations
  644. tk = 1;
  645. if (!strncmp(namebufp+1, "bold", 4) && namebufp[5] == '\0') tk = 0;
  646. if (!strncmp(namebufp+1, "italic", 6) && namebufp[7] == '\0') tk = 0;
  647. if (!strncmp(namebufp+1, "bolditalic", 10) && namebufp[11] == '\0') tk = 0;
  648. if (!strncmp(namebufp+1, "medium", 6) && namebufp[7] == '\0') tk = 0;
  649. if (!strncmp(namebufp+1, "regular", 7) && namebufp[8] == '\0') tk = 0;
  650. }
  651. if (tk == 1) continue; // skip font
  652. cbit = fbit = tbit = 0; // set font styles
  653. if (strstr(namebufp+1, "medium") || strstr(namebufp+1, "plain") ||
  654. strstr(namebufp+1, "regular")) cbit = 1;
  655. if (strstr(namebufp+1, "roman") && namebufp > tbufs[tj]) cbit = 1;
  656. if (strstr(namebufp+1, "bold") || strstr(namebufp+1, "italic")) cbit = 0;
  657. if (strstr(namebufp+1, "black") || strstr(namebufp+1, "bold") ||
  658. strstr(namebufp+1, "heavy") || strstr(namebufp+1, "semibold") ||
  659. strstr(namebufp+1, "wide")) fbit = 1;
  660. else if ((strstr(namebufp+1, "bd") || strstr(namebufp+1, "smbd")) &&
  661. namebufp > tbufs[tj]) fbit = 1;
  662. if (strstr(namebufp+1, "oblique") || strstr(namebufp+1, "inclined") ||
  663. strstr(namebufp+1, "italic") || strstr(namebufp+1, "slanted")) tbit = 1;
  664. else if ((strstr(namebufp+1, "it") || strstr(namebufp+1, "obl")) &&
  665. namebufp > tbufs[tj]) tbit = 1;
  666. if (cbit) face_[ti][0] = tfi[tj];
  667. if (fbit && !tbit && !face_[ti][1]) face_[ti][1] = tfi[tj]; // bold
  668. if (!fbit && tbit && !face_[ti][2]) face_[ti][2] = tfi[tj]; // italic
  669. if (fbit && tbit && !face_[ti][3]) face_[ti][3] = tfi[tj]; // plus
  670. }
  671. }
  672. for (ti = 0; ti < nfaces; ti ++) { // remove duplicate fonts
  673. for (tj = ti+1; tj < nfaces; tj ++)
  674. if (face_[ti][1] == face_[tj][1]) face_[tj][1] = 0; // sort face loop does the rest
  675. }
  676. for (ti = 0; ti < nfaces; ti ++) { // sort face table
  677. if (!face_[ti][2]) face_[ti][2] = face_[ti][0]; // no italic
  678. if (!face_[ti][3]) face_[ti][3] = face_[ti][1]; // no plus
  679. if (face_[ti][1]) { // move face
  680. for (tk = 0; tk < ti; tk ++) {
  681. if (!face_[tk][1]) { // first empty face
  682. for (tj = 0; tj <= 3; tj ++) {
  683. face_[tk][tj] = face_[ti][tj];
  684. face_[ti][tj] = 0;
  685. }
  686. break;
  687. }
  688. }
  689. }
  690. }
  691. for (nfaces = 1; nfaces < (int)sizeof(face_)/8; nfaces ++)
  692. if (!face_[nfaces][1]) break; // recount faces
  693. for (ti = 0, lnum = 0; ti < nfaces; ti ++) { // sort letter lut
  694. fnum = face_[ti][0];
  695. namep = Fl::get_font_name((Fl_Font)fnum, &temp);
  696. tnum = (uchar)tolower(*namep) - 97; // current letter, a = 0
  697. if (tnum != lnum && tnum < 27) // first instance of letter a..z
  698. flet_[tnum] = ti; // store face index
  699. lnum = tnum; // last letter
  700. }
  701. flet_[27] = nfaces; // last face index
  702. for (ti = 0; ti < nfaces; ti ++) { // face reference table
  703. for (tj = 0; tj <= 3; tj ++) { // fonts in face
  704. fnum = face_[ti][tj]; // font index
  705. if (fnum < (int)sizeof(fref_)) fref_[fnum] = ti; // store face index
  706. }
  707. }
  708. return nfaces; // we're done
  709. } // Fl_Help_View::build_faces()
  710. //
  711. // Fl_Help_View::clear_global_selection() - Clear text selection.
  712. //
  713. void Fl_Help_View::clear_global_selection()
  714. {
  715. if (selected) redraw(); // Set widget to draw
  716. selection_push_first = selection_push_last = 0;
  717. selection_drag_first = selection_drag_last = 0;
  718. selection_first = selection_last = 0;
  719. selected = 0;
  720. } // Fl_Help_View::clear_global_selection()
  721. //
  722. // Fl_Help_View::clear_selection() - Clear current text selection.
  723. //
  724. void Fl_Help_View::clear_selection()
  725. {
  726. if (current_view == this) clear_global_selection();
  727. } // Fl_Help_View::clear_selection()
  728. //
  729. // Fl_Help_View::cmp_targets() - Compare two targets.
  730. //
  731. int // O - Result of comparison
  732. Fl_Help_View::cmp_targets(const Fl_Help_Link *t0, // I - First target
  733. const Fl_Help_Link *t1) // I - Second target
  734. {
  735. return strcasecmp(t0->name, t1->name); // Target names
  736. } // Fl_Help_View::cmp_targets()
  737. //
  738. // Fl_Help_View::compare_targets() - replaced, struct used for d-pointer
  739. //
  740. int
  741. Fl_Help_View::compare_targets(const Fl_Help_Target *t0,
  742. const Fl_Help_Target *t1)
  743. {
  744. return 0;
  745. } // Fl_Help_View::compare_targets()
  746. //
  747. // Fl_Help_View::do_align() - Compute alignment for a line in a block.
  748. //
  749. int // O - New line
  750. Fl_Help_View::do_align(Fl_Help_Block *b, // I - Block to add to
  751. int li, // I - Current line - removed
  752. int xx, // I - Current X position
  753. int ca, // I - Current alignment
  754. int &sl) // IO - Starting link
  755. {
  756. int offset = 0; // Alignment offset
  757. switch (ca) {
  758. case RIGHT : // Right
  759. offset = b->w - xx - 6;
  760. break;
  761. case CENTER : // Center
  762. offset = (b->w - xx) / 2;
  763. break;
  764. default : // Left
  765. offset = 0;
  766. break;
  767. }
  768. b->line = b->x + offset; // Left starting position for line
  769. //if (li < 31) li ++;
  770. while (sl < nlinks_) {
  771. links_[sl].x += offset; // X offset of link text
  772. links_[sl].w += offset; // Width of link text
  773. sl ++;
  774. }
  775. return li;
  776. } // Fl_Help_View::do_align()
  777. //
  778. // Fl_Help_View::draw() - Draw the Fl_Help_View widget.
  779. //
  780. void Fl_Help_View::draw()
  781. {
  782. char *sp, // Buffer search ptr
  783. buf[1024], // Text buffer
  784. attr[1024], // Attribute buffer
  785. wattr[8], // Width attribute
  786. hattr[8], // Height attribute
  787. tag[4]; // tag/element 4-char buf
  788. const Fl_Help_Block *block; // Pointer to current block
  789. const char *ptr, // Pointer to text in block
  790. *attrptr, // Start of attributes ptr
  791. *tagptr; // Start of tag/element ptr
  792. int ti = 0, // temp loop var
  793. bi = 0, // Main loop var
  794. temp = 0, // temp var
  795. ss = 0, // Scrollbar size
  796. qch = 0, // Quote char
  797. baseh = 0, // baseline offset for images
  798. line = 0, // Current line
  799. xx = 0,
  800. yy = 0,
  801. ww = 0,
  802. hh = 0, // Current positions and sizes
  803. head = 0, // Head/body section flag
  804. pre = 0, // Pre text flag
  805. btag = 0, // tag/element fourcc int
  806. needspace = 0, // Do we need whitespace?
  807. underline = 0, // Underline text?
  808. tx = 0,
  809. ty = 0,
  810. tw = 0,
  811. th = 0, // Table cell positions and sizes
  812. linew = 0, // current line width
  813. imgw = 0, // Image width
  814. imgh = 0, // Image height
  815. brflag = 0; // br flag
  816. unsigned char font = 0; // Current font
  817. unsigned char fsize; // Current font size
  818. Fl_Boxtype bt = (box()) ? box() : FL_DOWN_BOX; // Box to draw
  819. Fl_Shared_Image *img = 0; // Shared image - rem'd NULL
  820. // Draw the scrollbar/s and box first
  821. ww = w();
  822. hh = h();
  823. initfont(font, fsize);
  824. draw_box(bt, x(), y(), ww, hh, bgcolor_);
  825. ss = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size();
  826. if (hscrollbar_.visible()) {
  827. draw_child(hscrollbar_);
  828. hh -= ss;
  829. ti ++;
  830. }
  831. if (scrollbar_.visible()) {
  832. draw_child(scrollbar_);
  833. ww -= ss;
  834. ti ++;
  835. }
  836. if (ti == 2) {
  837. fl_color(FL_GRAY);
  838. fl_rectf(x() + ww - Fl::box_dw(bt) + Fl::box_dx(bt),
  839. y() + hh - Fl::box_dh(bt) + Fl::box_dy(bt), ss, ss);
  840. }
  841. if (!value_) return;
  842. if (current_view == this && selected) {
  843. hv_selection_color = FL_SELECTION_COLOR;
  844. hv_selection_text_color = fl_contrast(textcolor_, FL_SELECTION_COLOR);
  845. }
  846. current_pos = 0;
  847. // Clip the drawing to the inside of the box
  848. fl_push_clip(x() + Fl::box_dx(bt), y() + Fl::box_dy(bt),
  849. ww - Fl::box_dw(bt), hh - Fl::box_dh(bt));
  850. fl_color(textcolor_);
  851. //printf("hh=%d ss=%d h()=%d\n",hh,ss,h());
  852. // Draw all visible blocks
  853. for (bi = 0, block = blocks_; bi < nblocks_; bi ++, block ++)
  854. if ((block->y + block->h) >= topline_ && block->y < (topline_ + h()))
  855. {
  856. line = 0;
  857. xx = block->line;
  858. yy = block->y - topline_;
  859. pre = block->pre;
  860. //if (!pre) {
  861. popfont(font, fsize);
  862. font = block->font; // default font for block
  863. fsize = block->fsize;
  864. pushfont(font, fsize);
  865. //}
  866. hh = 0;
  867. needspace = 0;
  868. brflag = 0;
  869. linew = 0;
  870. for (ptr = block->start, sp = buf; ptr < block->end; )
  871. {
  872. if ((*ptr == '<' || isspace((*ptr) & 255)) && sp > buf)
  873. {
  874. if (!head && !pre) // Draw normal text
  875. {
  876. *sp = '\0'; // Nul-terminate
  877. sp = buf;
  878. ww = (int)fl_width(buf); // Width of word in buf
  879. if (needspace && xx > block->x)
  880. xx += 4;//(int)fl_width(" ");
  881. baseh = 0; // add baseh offset for text
  882. if (block->maxh > 0 && block->imgy - topline_ == yy)
  883. baseh = block->maxh - fsize;
  884. //if (block->liney) baseh += block->liney;
  885. hv_draw(buf, xx + x() - leftline_, yy + y() + baseh); // replaces hv_draw(tbuf..
  886. if (underline) { // Add width for uline spaces after word
  887. temp = (isspace((*ptr) & 255)) ? (int)fl_width(" ") : 0;
  888. fl_xyline(xx + x() - leftline_, yy + y() + 1 + baseh,
  889. xx + x() - leftline_ + ww + temp);
  890. }
  891. xx += ww;
  892. current_pos = ptr - value_;
  893. if ((fsize + 2) > hh) hh = fsize + 2; // Set hh
  894. needspace = 0;
  895. }
  896. else if (!head && pre) // Draw pre text
  897. {
  898. // this code is buggy and conflicts with other stuff
  899. // don't think it's needed but leaving it just in case
  900. /* while (isspace((*ptr) & 255)) {
  901. if (*ptr == '\n') {
  902. *sp = '\0';
  903. sp = buf;
  904. hv_draw("|", xx + x() - leftline_, yy + y());
  905. if (underline)
  906. fl_xyline(xx + x() - leftline_, yy + y() + 1,
  907. xx + x() - leftline_ + (int)fl_width(buf));
  908. current_pos = ptr - value_;
  909. //if (line < 31) line ++;
  910. xx = block->line;
  911. yy += hh;
  912. hh = fsize + 2;
  913. }
  914. else if (*ptr == '\t') {
  915. ti = linew / (int)fl_width(" "); // number of chars
  916. temp = 8 - (ti & 7); // number of tabs
  917. for (ti = 0; ti < temp; ti ++) // pre tabs width fix
  918. *(sp ++) = ' ';
  919. }
  920. else
  921. *(sp ++) = ' ';
  922. if ((fsize + 2) > hh) hh = fsize + 2;
  923. ptr ++;
  924. }
  925. if (sp > buf) { the code below was in here */
  926. *sp = '\0'; // Nul-terminate
  927. sp = buf;
  928. ww = (int)fl_width(buf);
  929. //printf("b->x=%d b->w=%d xx=%d ww=%d linew=%d ptr=%c buf=%s\n",
  930. // block->x,block->w,xx,ww,linew,*ptr,buf);
  931. baseh = 0; // add baseh offset for pre text
  932. if (block->maxh > 0 && block->imgy - topline_ == yy)
  933. baseh = block->maxh - fsize;
  934. hv_draw(buf, xx + x() - leftline_, yy + y() + baseh);
  935. if (underline)
  936. fl_xyline(xx + x() - leftline_, yy + y() + 1 + baseh,
  937. xx + x() - leftline_ + ww);
  938. xx += ww;
  939. linew += ww;
  940. current_pos = ptr - value_;
  941. // } // if (sp > buf)
  942. needspace = 0;
  943. }
  944. else
  945. {
  946. sp = buf;
  947. while (isspace((*ptr) & 255)) ptr ++;
  948. current_pos = ptr - value_;
  949. }
  950. brflag = 0;
  951. }
  952. if (*ptr == '<')
  953. {
  954. tagptr = ptr; // Start of tag
  955. ptr ++;
  956. if (!strncmp(ptr, "!--", 3)) { // Found "!--"
  957. ptr += 3;
  958. if ((ptr = strstr(ptr, "-->"))) { // Skip comment - rem'd != 0
  959. ptr += 3;
  960. continue;
  961. }
  962. else
  963. break;
  964. }
  965. while (*ptr && *ptr != '>' && !isspace((*ptr) & 255))
  966. if (sp < (buf + sizeof(buf) - 1))
  967. *(sp ++) = *(ptr ++); // added ()
  968. else
  969. ptr ++;
  970. *sp = '\0'; // Nul-terminate
  971. sp = buf;
  972. attrptr = ptr; // Start of attributes
  973. while (*ptr && *ptr != '>') ptr ++;
  974. if (*ptr == '>') ptr ++;
  975. // Set the supposed start of printed eord here
  976. current_pos = ptr - value_;
  977. btag = strlen(buf); // store strlen
  978. if (btag > 4) btag = 4; // limit
  979. for (ti = 0; ti < btag; ti ++) // abbreviate tag, to uppercase
  980. tag[ti] = toupper(buf[ti]);
  981. for (ti = btag; ti < 4; ti ++) // set chars after to nul
  982. tag[ti] = 0;
  983. if (buf[0] != '/' && btag > 3) tag[3] = 0; // eg. HTML=HTM
  984. btag = CMD(tag[0],tag[1],tag[2],tag[3]); // tag fourcc int
  985. // End of command reached
  986. if (btag == CMD('A',0,0,0)) // 'A'
  987. {
  988. if (get_attr(attrptr, "HREF", attr, sizeof(attr))) {
  989. fl_color(linkcolor_);
  990. underline = 1;
  991. }
  992. }
  993. else if (btag == CMD('/','A',0,0)) // '/A'
  994. {
  995. fl_color(textcolor_);
  996. underline = 0;
  997. }
  998. else if (btag == CMD('B',0,0,0) ||
  999. btag == CMD('S','T','R',0)) // 'B' 'STRONG'
  1000. {
  1001. font = font_style(font, FL_BOLD);
  1002. pushfont(font, fsize);
  1003. }
  1004. else if (btag == CMD('/','B',0,0) ||
  1005. btag == CMD('/','S','T','R')) // '/B' '/STRONG'
  1006. {
  1007. popfont(font, fsize);
  1008. }
  1009. else if (btag == CMD('B','L','O',0) ||
  1010. btag == CMD('D','L',0,0) ||
  1011. btag == CMD('U','L',0,0) ||
  1012. btag == CMD('O','L',0,0) ||
  1013. btag == CMD('D','D',0,0) ||
  1014. btag == CMD('D','T',0,0)) // 'BLOCKQUOTE' 'DL'OL'UL'
  1015. {
  1016. }
  1017. else if (btag == CMD('/','B','L','O') ||
  1018. btag == CMD('/','D','L',0) ||
  1019. btag == CMD('/','O','L',0) ||
  1020. btag == CMD('/','U','L',0)) // '/BLOCKQUOTE' '/DL'/OL'/UL'
  1021. {
  1022. }
  1023. else if (btag == CMD('B','O','D',0)) // 'BODY'
  1024. {
  1025. head = 0;
  1026. }
  1027. else if (btag == CMD('B','R',0,0)) // 'BR'
  1028. {
  1029. }
  1030. else if (btag == CMD('C','E','N',0)) // 'CENTER'
  1031. {
  1032. }
  1033. else if (btag == CMD('C','O','D',0) ||
  1034. btag == CMD('T','T',0,0)) // 'CODE' 'TT'
  1035. {
  1036. font = monofont_;
  1037. pushfont(font, fsize);
  1038. }
  1039. else if (btag == CMD('/','C','O','D') ||
  1040. btag == CMD('/','T','T',0)) // '/CODE' '/TT'
  1041. {
  1042. popfont(font, fsize);
  1043. }
  1044. else if (btag == CMD('D','I','V',0)) // 'DIV'
  1045. {
  1046. }
  1047. else if (btag == CMD('F','O','N',0)) // 'FONT'
  1048. {
  1049. if (get_attr(attrptr, "COLOR", attr, sizeof(attr)))
  1050. fl_color(get_color(attr, textcolor_));
  1051. if (get_attr(attrptr, "FACE", attr, sizeof(attr)))
  1052. font = font_face(attr);
  1053. //tempsize = fsize;
  1054. if (get_attr(attrptr, "SIZE", attr, sizeof(attr))) {
  1055. if (isdigit(attr[0])) // Absolute size
  1056. fsize = (int)(fontsize_ * pow(1.2, atof(attr) - 3.0));
  1057. else // Relative size
  1058. fsize = (int)(fsize * pow(1.2, atof(attr) - 3.0));
  1059. }
  1060. pushfont(font, fsize);
  1061. if (fsize + 2 > hh) hh = fsize + 2; // set hh
  1062. }
  1063. else if (btag == CMD('/','F','O','N')) // '/FONT'
  1064. {
  1065. fl_color(textcolor_);
  1066. //tempsize = fsize;
  1067. popfont(font, fsize);
  1068. if (fsize + 2 > hh) hh = fsize + 2; // set hh
  1069. }
  1070. else if (tag[0] == 'H' && isdigit(tag[1])) // 'H1'
  1071. {
  1072. if (tag[1] < '7') { // ignore if > h6
  1073. font = font_style(font, FL_BOLD);
  1074. switch (tag[1]) { // header sizes
  1075. case '1' : fsize = 24; break;
  1076. case '2' : fsize = 18; break;
  1077. case '3' : fsize = 16; break;
  1078. case '4' : fsize = 14; break;
  1079. case '5' : fsize = 12; break;
  1080. case '6' : fsize = 10; break;
  1081. }
  1082. pushfont(font, fsize);
  1083. }
  1084. }
  1085. else if (btag == CMD('/','H',tag[2],0) && isdigit(tag[2])) // '/H1'
  1086. {
  1087. if (tag[2] < '7') // ignore if > h6
  1088. popfont(font, fsize);
  1089. }
  1090. else if (btag == CMD('H','E','A',0)) // 'HEAD'
  1091. {
  1092. head = 1;
  1093. }
  1094. else if (btag == CMD('/','H','E','A')) // '/HEAD'
  1095. {
  1096. head = 0;
  1097. }
  1098. else if (btag == CMD('H','R',0,0)) // 'HR'
  1099. { // rem'd new line, added hr shadow
  1100. tx = x() - leftline_; // hr x
  1101. ty = yy + y() - fsize; // hr y
  1102. int height, width, lx1, lx2, half1, half2;
  1103. int isStandard = 1;
  1104. char myattr[8], *mydash, myattr_dash[9];
  1105. if(get_attr ( attrptr, "COLOR", myattr, sizeof ( myattr ) ))
  1106. {
  1107. fl_color(get_color( myattr, FL_BLACK ));
  1108. isStandard = 0;
  1109. } else fl_color(FL_BLACK);
  1110. if(get_attr ( attrptr, "DASH", myattr_dash, sizeof ( myattr_dash ) ))
  1111. {
  1112. for(unsigned int i=0; i<sizeof(myattr_dash); i++)
  1113. if(myattr_dash[i] > '0')
  1114. myattr_dash[i] -= '0';
  1115. mydash = myattr_dash;
  1116. isStandard = 0;
  1117. }
  1118. else mydash = NULL;
  1119. if(get_attr ( attrptr, "HEIGHT", myattr, sizeof ( myattr ) ))
  1120. {
  1121. height = atoi ( myattr );
  1122. fl_line_style(FL_SOLID | FL_CAP_SQUARE, height, mydash);
  1123. isStandard = 0;
  1124. }
  1125. if(get_attr ( attrptr, "WIDTH", myattr, sizeof ( myattr ) )){
  1126. width = get_length( myattr );
  1127. isStandard = 0;
  1128. }
  1129. else
  1130. width = block->w + tx;
  1131. switch ( get_align ( attrptr, LEFT ) )
  1132. {
  1133. case CENTER :
  1134. half1 = block->w / 2;
  1135. half2 = width / 2;
  1136. lx1 = block->x + tx + half1 - half2;
  1137. lx2 = block->w + tx - half1 + half2;
  1138. isStandard = 0;
  1139. break;
  1140. case RIGHT :
  1141. lx1 = block->w + tx - width;
  1142. lx2 = block->w + tx;
  1143. isStandard = 0;
  1144. break;
  1145. default :
  1146. lx1 = block->x + tx;
  1147. lx2 = width;
  1148. break;
  1149. }
  1150. if(isStandard){
  1151. fl_line(block->x + tx, ty, block->w + tx, ty);
  1152. fl_color(224, 224, 224); // light grey
  1153. fl_line(block->x + tx, ty + 1, block->w + tx, ty + 1); // shadow
  1154. } else {
  1155. fl_line ( lx1, ty, lx2, ty );
  1156. fl_line_style(0); //reset line style
  1157. }
  1158. fl_color(textcolor_); // reset
  1159. hh = fsize + 2; // set hh
  1160. }
  1161. else if (btag == CMD('H','T','M',0)) // 'HTML'
  1162. {
  1163. }
  1164. else if (btag == CMD('I',0,0,0) ||
  1165. btag == CMD('E','M',0,0)) // 'I' 'EM'
  1166. {
  1167. font = font_style(font, FL_ITALIC);
  1168. pushfont(font, fsize);
  1169. }
  1170. else if (btag == CMD('/','I',0,0) ||
  1171. btag == CMD('/','E','M',0)) // '/I' '/EM'
  1172. {
  1173. popfont(font, fsize);
  1174. }
  1175. else if (btag == CMD('I','M','G',0)) // 'IMG'
  1176. {
  1177. imgw = imgh = 0; // reset
  1178. if (get_attr(attrptr, "WIDTH", wattr, sizeof(wattr)))
  1179. imgw = get_length(wattr);
  1180. if (get_attr(attrptr, "HEIGHT", hattr, sizeof(hattr)))
  1181. imgh = get_length(hattr);
  1182. img = 0; // rem'd NULL
  1183. if (get_attr(attrptr, "SRC", attr, sizeof(attr))) {
  1184. img = get_image(attr, imgw, imgh);
  1185. if (!imgw) imgw = img->w();
  1186. if (!imgh) imgh = img->h();
  1187. }
  1188. if (!imgw || !imgh) {
  1189. if (!get_attr(attrptr, "ALT", attr, sizeof(attr))) // rem'd == 0
  1190. strcpy(attr, "IMG");
  1191. }
  1192. ww = imgw;
  1193. if (needspace && xx > block->x)
  1194. xx += (int)fl_width(" ");
  1195. if (img) {
  1196. baseh = block->maxh - imgh; // add baseh offset
  1197. img->draw(xx + x() - leftline_,
  1198. yy + y() - fl_height() + fl_descent() + baseh); // rem'd + 2
  1199. // Seb was here - freeing broken_image causes an XServer XFreePixmap crash
  1200. if ((void*)img != &broken_image) img->release();
  1201. }
  1202. xx += ww;
  1203. if (imgh + 2 > hh) hh = imgh + 2; // Set img hh
  1204. needspace = 0;
  1205. brflag = 0;
  1206. }
  1207. else if (btag == CMD('K','B','D',0)) // 'KBD'
  1208. {
  1209. font = font_style(monofont_, FL_BOLD);
  1210. pushfont(font, fsize);
  1211. }
  1212. else if (btag == CMD('/','K','B','D')) // '/KBD'
  1213. {
  1214. popfont(font, fsize);
  1215. }
  1216. else if (btag == CMD('L','I',0,0)) // 'LI'
  1217. {
  1218. // rem'd hv_draw and symbol font stuff
  1219. tx = xx - fsize + x() - leftline_; // bullet x
  1220. ty = yy + y() - 6; // bullet y
  1221. get_attr(attrptr, "TYPE", attr, sizeof(attr)); // bullet type
  1222. if (!strncasecmp(attr, "disc", 4) ||
  1223. !strncasecmp(attr, "disk", 4)) { // li > ul > ul nest
  1224. fl_arc(tx, ty, 5, 5, 0, 360);
  1225. fl_rectf(tx + 1, ty + 1, 3, 3);
  1226. }
  1227. else if (!strncasecmp(attr, "circle", 6))
  1228. fl_arc(tx, ty, 5, 5, 0, 360);
  1229. else if (!strncasecmp(attr, "square", 6))
  1230. fl_rectf(tx, ty, 5, 5);
  1231. else if (block->type == 1) { // disc/disk
  1232. fl_arc(tx, ty, 5, 5, 0, 360);
  1233. fl_rectf(tx + 1, ty + 1, 3, 3);
  1234. }
  1235. else if (block->type == 2) // circle
  1236. fl_arc(tx, ty, 5, 5, 0, 360);
  1237. else if (block->type >= 3) // square
  1238. fl_rectf(tx, ty, 5, 5);
  1239. else { // default
  1240. fl_arc(tx, ty, 5, 5, 0, 360);
  1241. fl_rectf(tx + 1, ty + 1, 3, 3);
  1242. }
  1243. }
  1244. else if (btag == CMD('/','L','I',0)) // '/LI'
  1245. {
  1246. }
  1247. else if (btag == CMD('N','O','S',0)) // 'NOSCRIPT'
  1248. { // we don't support scripting so we won't skip this
  1249. }
  1250. else if (btag == CMD('P',0,0,0)) // 'P'
  1251. {
  1252. }
  1253. else if (btag == CMD('P','R','E',0)) // 'PRE'
  1254. {
  1255. linew = 0;
  1256. pre = 1;
  1257. //font = monofont_;
  1258. //fsize = fontsize_;
  1259. //pushfont(font, fsize);
  1260. tx = block->x - leftline_;
  1261. ty = block->y - topline_ - fsize;
  1262. tw = block->w - block->x - 2;
  1263. th = block->h + fsize + (fsize / 4);
  1264. if (tx < 0) {
  1265. tw += tx;
  1266. tx = 0;
  1267. }
  1268. if (ty < 0) {
  1269. th += ty;
  1270. ty = 0;
  1271. }
  1272. tx += x();
  1273. ty += y();
  1274. if (block->bgcolor != bgcolor_) {
  1275. fl_color(block->bgcolor);
  1276. fl_rectf(tx, ty, tw, th);
  1277. fl_color(textcolor_);
  1278. }
  1279. if (block->border){
  1280. fl_rect ( tx, ty, tw, th );
  1281. }
  1282. }
  1283. else if (btag == CMD('/','P','R','E')) // '/PRE'
  1284. {
  1285. //popfont(font, fsize);
  1286. pre = 0;
  1287. }
  1288. else if (btag == CMD('S','C','R',0)) // 'SCRIPT'
  1289. {
  1290. while (ptr) { // skip scripting
  1291. ptr = strstr(ptr, "</");
  1292. if (!strncasecmp(ptr, "</SCRIPT>", 9)) break;
  1293. }
  1294. if (ptr) { // found </script>
  1295. ptr += 9;
  1296. continue;
  1297. }
  1298. else // not found
  1299. break;
  1300. }
  1301. else if (btag == CMD('T','A','B',0)) // 'TABLE'
  1302. {
  1303. }
  1304. else if (btag == CMD('T','D',0,0) ||
  1305. btag == CMD('T','H',0,0)) // 'TD' 'TH'
  1306. {
  1307. /*if (btag == CMD('T','H',0,0))
  1308. font = serifont_ | FL_BOLD;
  1309. else
  1310. font = serifont_;
  1311. fsize = fontsize_;
  1312. pushfont(font, fsize);*/
  1313. fl_color(textcolor_); // fixes /a td bug
  1314. underline = 0;
  1315. tx = block->x - 4 - leftline_; //-4 -> left padding
  1316. ty = block->y - topline_ - fsize - 3; //-3 -> top padding
  1317. tw = block->w - block->x + (tr_td_adjust_ ? 6 : 7); // +7 -> right size
  1318. th = block->h + fsize - (tr_td_adjust_ ? 6 : 5); // -5 -> bottom size
  1319. if (tx < 0) {
  1320. tw += tx;
  1321. tx = 0;
  1322. }
  1323. if (ty < 0) {
  1324. th += ty;
  1325. ty = 0;
  1326. }
  1327. tx += x();
  1328. ty += y();
  1329. if (block->bgcolor != bgcolor_) {
  1330. fl_color(block->bgcolor);
  1331. fl_rectf(tx, ty, tw, th);
  1332. fl_color(textcolor_);
  1333. }
  1334. if (block->border){
  1335. fl_color ( block->border_color );
  1336. fl_line_style(FL_SOLID | FL_CAP_SQUARE, block->border, NULL);
  1337. fl_rect ( tx, ty, tw, th );
  1338. fl_line_style(0);
  1339. fl_color ( textcolor_ );
  1340. }
  1341. }
  1342. else if (btag == CMD('/','T','D',0) ||
  1343. btag == CMD('/','T','H',0)) // '/TD' '/TH'
  1344. {
  1345. //popfont(font, fsize);
  1346. }
  1347. else if (btag == CMD('T','I','T',0)) // 'TITLE'
  1348. {
  1349. head = 1;
  1350. }
  1351. else if (btag == CMD('T','R',0,0)) // 'TR'
  1352. {
  1353. }
  1354. else if (btag == CMD('U',0,0,0)) // 'U'
  1355. {
  1356. underline = 1;
  1357. }
  1358. else if (btag == CMD('/','U',0,0)) // '/U'
  1359. {
  1360. underline = 0;
  1361. }
  1362. else if (btag == CMD('V','A','R',0)) // 'VAR'
  1363. {
  1364. font = font_style(monofont_, FL_ITALIC);
  1365. pushfont(font, fsize);
  1366. }
  1367. else if (btag == CMD('/','V','A','R')) // '/VAR'
  1368. {
  1369. popfont(font, fsize);
  1370. }
  1371. else if (btag == CMD('A','B','B',0) || // 'ABBR'
  1372. btag == CMD('A','C','R',0) || // 'ACRONYM'
  1373. btag == CMD('A','D','D',0) || // 'ADDRESS'
  1374. btag == CMD('A','P','P',0) || // 'APPLET'
  1375. btag == CMD('A','R','E',0) || // 'AREA'
  1376. btag == CMD('B','A','S',0) || // 'BASE' 'BASEFONT'
  1377. btag == CMD('B','D','O',0) || // 'BDO'
  1378. btag == CMD('B','G','S',0) || // 'BGSOUND'
  1379. btag == CMD('B','I','G',0) || // 'BIG'
  1380. btag == CMD('B','L','I',0) || // 'BLINK'
  1381. btag == CMD('B','U','T',0) || // 'BUTTON'
  1382. btag == CMD('C','A','P',0) || // 'CAPTION'
  1383. btag == CMD('C','I','T',0) || // 'CITE'
  1384. btag == CMD('C','O','L',0) || // 'COL' 'COLGROUP'
  1385. btag == CMD('D','E','L',0) || // 'DEL'
  1386. btag == CMD('D','F','N',0) || // 'DFN'
  1387. btag == CMD('D','I','R',0) || // 'DIR'
  1388. btag == CMD('E','M','B',0) || // 'EMBED'
  1389. btag == CMD('F','I','E',0) || // 'FIELDSET'
  1390. btag == CMD('F','O','R',0) || // 'FORM'
  1391. btag == CMD('F','R','A',0) || // 'FRAME' 'FRAMESET'
  1392. btag == CMD('I','F','R',0) || // 'IFRAME'
  1393. btag == CMD('I','N','P',0) || // 'INPUT'
  1394. btag == CMD('I','N','S',0) || // 'INS'
  1395. btag == CMD('I','S','I',0) || // 'ISINDEX'
  1396. btag == CMD('L','A','B',0) || // 'LABEL'
  1397. btag == CMD('L','E','G',0) || // 'LEGEND'
  1398. btag == CMD('L','I','N',0) || // 'LINK'
  1399. btag == CMD('M','A','P',0) || // 'MAP'
  1400. btag == CMD('M','A','R',0) || // 'MARQUEE'
  1401. btag == CMD('M','E','N',0) || // 'MENU'
  1402. btag == CMD('M','E','T',0) || // 'META'
  1403. btag == CMD('M','U','L',0) || // 'MULTICOL'
  1404. btag == CMD('N','O','B',0) || // 'NOBR'
  1405. btag == CMD('N','O','F',0) || // 'NOFRAMES'
  1406. btag == CMD('O','B','J',0) || // 'OBJECT'
  1407. btag == CMD('O','P','T',0) || // 'OPTGROUP' 'OPTION'
  1408. btag == CMD('P','A','R',0) || // 'PARAM'
  1409. btag == CMD('Q',0,0,0) || // 'Q'
  1410. btag == CMD('S',0,0,0) || // 'S'
  1411. btag == CMD('S','A','M',0) || // 'SAMP'
  1412. btag == CMD('S','E','L',0) || // 'SELECT'
  1413. btag == CMD('S','M','A',0) || // 'SMALL'
  1414. btag == CMD('S','P','A',0) || // 'SPACER' 'SPAN'
  1415. btag == CMD('S','T','R',0) || // 'STRIKE'
  1416. btag == CMD('S','T','Y',0) || // 'STYLE'
  1417. btag == CMD('S','U','B',0) || // 'SUB'
  1418. btag == CMD('S','U','P',0) || // 'SUP'
  1419. btag == CMD('T','B','O',0) || // 'TBODY'
  1420. btag == CMD('T','E','X',0) || // 'TEXTAREA'
  1421. btag == CMD('T','F','O',0) || // 'TFOOT'
  1422. btag == CMD('T','H','E',0) || // 'THEAD'
  1423. btag == CMD('W','B','R',0) || // 'WBR'
  1424. btag == CMD('X','M','P',0)) // 'XMP'
  1425. ; // unsupported tags
  1426. else if (tag[0] == '!' && isalpha(tag[1])) // '!DOCTYPE' etc
  1427. ;
  1428. else if (tag[0] == '?' && isalpha(tag[1])) // '?XMP' etc
  1429. ;
  1430. else if (tag[0] == '/' && isalpha(tag[1])) // unrecognized end tag
  1431. ;
  1432. else if (!head) // unrecognized tag so draw it
  1433. {
  1434. hv_draw("<", xx + x() - leftline_, yy + y()); // draw '<' char
  1435. xx += (int)fl_width("<"); // add width of '<' char
  1436. linew += (int)fl_width("<");
  1437. ptr = tagptr + 1; // start of tag + 1
  1438. }
  1439. } // if (*ptr == '<')
  1440. else if (*ptr == '\n' && pre) // '\n' char in pre
  1441. {
  1442. *sp = '\0'; // Nul-terminate
  1443. sp = buf;
  1444. hv_draw(buf, xx + x() - leftline_, yy + y());
  1445. //hh = fsize + 2; // Set hh
  1446. linew = 0;
  1447. needspace = 0;
  1448. ptr ++;
  1449. current_pos = ptr - value_;
  1450. }
  1451. else if (isspace((*ptr) & 255)) // ' ' '\t'\n'\v'\f'\r' chars
  1452. {
  1453. if (pre) {
  1454. if (*ptr == ' ')
  1455. *(sp ++) = ' '; // added ()
  1456. else if (*ptr == '\t') {
  1457. ti = linew / (int)fl_width(" "); // number of chars, monospace
  1458. temp = 8 - (ti & 7); // number of tabs 1..8
  1459. for (ti = 0; ti < temp; ti ++) // pre tabs width fix
  1460. *(sp ++) = ' '; // added ()
  1461. }
  1462. }
  1463. ptr ++;
  1464. if (!pre) current_pos = ptr - value_;
  1465. needspace = 1; // Set need space flag
  1466. }
  1467. else if (*ptr == '&') // '&' char ref
  1468. {
  1469. ptr ++;
  1470. qch = quote_char(ptr);
  1471. if (qch < 0) // Not char ref
  1472. *(sp ++) = '&';
  1473. else { // replaces else if (temp == 0)
  1474. *(sp ++) = qch; // added ()
  1475. ptr = strchr(ptr, ';') + 1; // skip past semi-colon char
  1476. }
  1477. if ((fsize + 2) > hh) hh = fsize + 2; // Set hh
  1478. }
  1479. else
  1480. {
  1481. *(sp ++) = *(ptr ++); // added ()
  1482. if ((fsize + 2) > hh) hh = fsize + 2; // Set hh
  1483. }
  1484. } // for (ptr = block->start ...)
  1485. *sp = '\0'; // Nul-terminate
  1486. if (sp > buf) // Still something left to parse
  1487. {
  1488. ww = (int)fl_width(buf); // Width of word
  1489. if (!head && !pre) { // Normal text
  1490. if (needspace && xx > block->x)
  1491. xx += (int)fl_width(" ");
  1492. }
  1493. if (!head) { // Draw text
  1494. baseh = 0; // add baseh offset for missed text
  1495. if (block->maxh > 0 && block->imgy - topline_ == yy)
  1496. baseh = block->maxh - fsize;
  1497. //if (block->liney) baseh += block->liney;
  1498. hv_draw(buf, xx + x() - leftline_, yy + y() + baseh);
  1499. if (underline)
  1500. fl_xyline(xx + x() - leftline_, yy + y() + 1 + baseh,
  1501. xx + x() - leftline_ + ww);
  1502. current_pos = ptr - value_;
  1503. }
  1504. }
  1505. } // for (bi = 0 ...)
  1506. fl_pop_clip();
  1507. } // Fl_Help_View::draw()
  1508. //
  1509. // Fl_Help_View::end_selection() - End text selection.
  1510. //
  1511. void Fl_Help_View::end_selection(int cb) // I - Set clipboard, opt
  1512. {
  1513. if (!selected || current_view != this) return;
  1514. // Convert the select part of our html text into some kind of
  1515. // somewhat readable ASCII and store it in the selection buffer
  1516. char spacec = 0, pre = 0, tempc = 0, endc = 0;
  1517. int len = strlen(value_),
  1518. in = 0, xx = 0;
  1519. char *text = (char*)malloc(len + 1),
  1520. *dp = text;
  1521. const char *sp = value_,
  1522. *cmdp,
  1523. *srcp;
  1524. while (true) // was for (;;)
  1525. {
  1526. tempc = *(sp ++); // added ()
  1527. if (tempc == 0) break;
  1528. if (tempc == '<') { // Begin of some html command. Skip until we find a '>'
  1529. cmdp = sp;
  1530. while (true) { // was for (;;)
  1531. tempc = *(sp ++); // added ()
  1532. if (tempc == 0 || tempc == '>') break;
  1533. }
  1534. if (tempc == 0) break;
  1535. // Do something with this command, the replacement string must
  1536. // not be longer that the command itself plus '<' and '>'
  1537. srcp = 0; // rem'd NULL
  1538. switch (command(cmdp)) {
  1539. case CMD('p','r','e', 0 ): pre = 1; break;
  1540. case CMD('/','p','r','e'): pre = 0; break;
  1541. case CMD('t','d', 0 , 0 ):
  1542. case CMD('p', 0 , 0 , 0 ):
  1543. case CMD('/','p', 0 , 0 ):
  1544. case CMD('b','r', 0 , 0 ): srcp = "\n"; break;
  1545. case CMD('l','i', 0 , 0 ): srcp = "\n * "; break;
  1546. case CMD('/','h','1', 0 ):
  1547. case CMD('/','h','2', 0 ):
  1548. case CMD('/','h','3', 0 ):
  1549. case CMD('/','h','4', 0 ):
  1550. case CMD('/','h','5', 0 ):
  1551. case CMD('/','h','6', 0 ): srcp = "\n\n"; break;
  1552. case CMD('t','r', 0 , 0 ):
  1553. case CMD('h','1', 0 , 0 ):
  1554. case CMD('h','2', 0 , 0 ):
  1555. case CMD('h','3', 0 , 0 ):
  1556. case CMD('h','4', 0 , 0 ):
  1557. case CMD('h','5', 0 , 0 ):
  1558. case CMD('h','6', 0 , 0 ): srcp = "\n\n"; break;
  1559. case CMD('d','t', 0 , 0 ): srcp = "\n "; break;
  1560. case CMD('d','d', 0 , 0 ): srcp = "\n - "; break;
  1561. }
  1562. in = sp - value_;
  1563. if (srcp && in > selection_first && in <= selection_last) {
  1564. while (*srcp)
  1565. *(dp ++) = *(srcp ++); // added ()
  1566. tempc = srcp[-1];
  1567. spacec = (isspace(tempc & 255)) ? ' ' : tempc;
  1568. }
  1569. continue;
  1570. }
  1571. if (tempc == '&') { // Special characters
  1572. xx = quote_char(sp);
  1573. if (xx >= 0) {
  1574. tempc = (char)xx;
  1575. while (true) { // was for (;;)
  1576. endc = *(sp ++); // added ()
  1577. if (!endc || endc == ';') break;
  1578. }
  1579. }
  1580. }
  1581. in = sp - value_;
  1582. if (in > selection_first && in <= selection_last) {
  1583. if (!pre && isspace(tempc & 255)) tempc = ' ';
  1584. if (spacec != ' ' || tempc != ' ')
  1585. *(dp ++) = tempc; // added ()
  1586. spacec = tempc;
  1587. }
  1588. }
  1589. *dp = 0;
  1590. Fl::copy(text, strlen(text), cb);
  1591. free(text);
  1592. } // Fl_Help_View::end_selection()
  1593. //
  1594. // Fl_Help_View::extend_selection() - Extend current text selection.
  1595. //
  1596. char // O - True if text selection changed
  1597. Fl_Help_View::extend_selection()
  1598. {
  1599. if (Fl::event_is_click()) return 0;
  1600. //printf("old selection_first=%d, selection_last=%d\n",
  1601. // selection_first, selection_last);
  1602. int sf = selection_first,
  1603. sl = selection_last;
  1604. selected = 1;
  1605. mouse_x = Fl::event_x();
  1606. mouse_y = Fl::event_y();
  1607. draw_mode = 2; // End selection mode
  1608. fl_begin_offscreen(Fl_Help_View_buffer);
  1609. draw();
  1610. fl_end_offscreen();
  1611. draw_mode = 0;
  1612. if (selection_push_first < selection_drag_first) {
  1613. selection_first = selection_push_first;
  1614. }
  1615. else {
  1616. selection_first = selection_drag_first;
  1617. }
  1618. if (selection_push_last > selection_drag_last) {
  1619. selection_last = selection_push_last;
  1620. }
  1621. else {
  1622. selection_last = selection_drag_last;
  1623. }
  1624. //printf("new selection_first=%d, selection_last=%d\n",
  1625. // selection_first, selection_last);
  1626. if (sf != selection_first || sl != selection_last) { // was ! =
  1627. // puts("REDRAW!!!\n");
  1628. return 1;
  1629. }
  1630. else {
  1631. // puts("");
  1632. return 0;
  1633. }
  1634. } // Fl_Help_View::extend_selection()
  1635. //
  1636. // Fl_Help_View::fileislink() - Was link clicked or nav button?
  1637. //
  1638. int Fl_Help_View::fileislink() // O - Link clicked
  1639. {
  1640. return d->islink;
  1641. }
  1642. //
  1643. // Fl_Help_View::filepath() - Set value file path string.
  1644. //
  1645. void Fl_Help_View::filepath(const char *fp) // I - Current file path
  1646. {
  1647. if (!fp) return; // null
  1648. d->ispath = 1; // path is used
  1649. if (!d->islink) // nav button
  1650. strlcpy(d->lpath, d->path, sizeof(d->lpath)); // set last path
  1651. strlcpy(d->path, fp, sizeof(d->path)); // set path
  1652. }
  1653. //
  1654. // Fl_Help_View::filepath() - Get value file path string.
  1655. //
  1656. char *Fl_Help_View::filepath() // O - Current file path
  1657. {
  1658. return d->path;
  1659. }
  1660. //
  1661. // Fl_Help_View::find() - Find the specified string.
  1662. //
  1663. int // O - Matching position or -1 if not found
  1664. Fl_Help_View::find(const char *sp, // I - String to find
  1665. int pos) // I - Starting position, opt
  1666. {
  1667. int ti = 0, // Temp looping var
  1668. cref = 0; // Current char ref
  1669. Fl_Help_Block *block; // Current block
  1670. const char *bptr, // Block matching pointer
  1671. *cptr, // Start of current comparison pointer
  1672. *sptr; // Search string pointer
  1673. // Range check input and value
  1674. if (!sp || !value_) return -1;
  1675. if (pos < 0 || pos >= (int)strlen(value_))
  1676. pos = 0;
  1677. else if (pos > 0)
  1678. pos ++;
  1679. // Look for the string
  1680. for (ti = nblocks_, block = blocks_; ti > 0; ti --, block ++)
  1681. {
  1682. if (block->end < (value_ + pos))
  1683. continue;
  1684. if (block->start < (value_ + pos))
  1685. bptr = value_ + pos;
  1686. else
  1687. bptr = block->start;
  1688. for (sptr = sp, cptr = bptr; *sptr && *bptr && bptr < block->end; bptr ++)
  1689. {
  1690. if (*bptr == '<') { // Skip to end of element
  1691. while (*bptr && bptr < block->end && *bptr != '>')
  1692. bptr ++;
  1693. continue;
  1694. }
  1695. else if (*bptr == '&') { // Decode HTML entity
  1696. cref = quote_char(bptr + 1);
  1697. if (cref < 0) // Not char ref
  1698. cref = '&';
  1699. else
  1700. bptr = strchr(bptr + 1, ';') + 1;
  1701. }
  1702. else
  1703. cref = *bptr;
  1704. if (tolower(*sptr) == tolower(cref))
  1705. sptr ++;
  1706. else { // No match, so reset to start of search
  1707. sptr = sp;
  1708. cptr ++;
  1709. bptr = cptr;
  1710. }
  1711. } // for (sptr = sp ...)
  1712. if (!*sptr) { // Found a match!
  1713. topline(block->y - block->h);
  1714. return (block->end - value_);
  1715. }
  1716. } // for (ti = nblocks_ ...)
  1717. return -1; // No match!
  1718. } // Fl_Help_View::find()
  1719. //
  1720. // Fl_Help_View::find_link() - Find the link at the given position.
  1721. //
  1722. Fl_Help_Link * // O - Link pointer
  1723. Fl_Help_View::find_link(int xx, // I - X position
  1724. int yy) // I - Y position
  1725. {
  1726. int ti = 0;
  1727. Fl_Help_Link *linkp;
  1728. for (ti = nlinks_, linkp = links_; ti > 0; ti --, linkp ++) {
  1729. if (xx >= linkp->x && xx < linkp->w &&
  1730. yy >= linkp->y && yy < linkp->h)
  1731. break;
  1732. }
  1733. return (ti) ? linkp : 0; // Was link found? - rem'd NULL
  1734. } // Fl_Help_View::find_link()
  1735. //
  1736. // Fl_Help_View::follow_link() - Follow the specified link.
  1737. //
  1738. void Fl_Help_View::follow_link(Fl_Help_Link *lp) // I - Link pointer
  1739. {
  1740. char target[32], // Current target
  1741. dir[1024], // Current directory
  1742. temp[1024], // Temporary filename
  1743. *tptr,
  1744. *sptr,
  1745. *dirp; // Pointer into temporary filename
  1746. const char *namep = lp->filename; // link filename
  1747. const char *vlink_name;
  1748. char *link_to_free = NULL;
  1749. if( link_ ){ //call link function to give it a chance to cancel it
  1750. vlink_name = (*link_)(this, namep, lp->name);
  1751. if(!vlink_name) return;
  1752. if(vlink_name != namep){
  1753. link_to_free = (char*) vlink_name;
  1754. namep = vlink_name;
  1755. }
  1756. }
  1757. strlcpy(target, lp->name, sizeof(target));
  1758. clear_selection(); // Clear text selection
  1759. set_changed(); // Set widget value was changed
  1760. //printf(" follow_link namep=(%s)\n",namep);
  1761. //printf(" follow_link filename_=(%s)\n",filename_);
  1762. if (namep[0] && strcmp(namep, filename_)) // Link not same as filename_
  1763. {
  1764. if (strchr(directory_, ':') && !strchr(namep, ':')) // rem'd != 0 and == 0
  1765. { // dir is absolute, lp is relative
  1766. if (namep[0] == '/') { // lp is absolute
  1767. strlcpy(temp, directory_, sizeof(temp));
  1768. if ((tptr = strrchr(strchr(temp, ':') + 3, '/')) != 0) // get filename
  1769. strlcpy(tptr, namep, sizeof(temp)-(tptr - temp)); // remove filename
  1770. else
  1771. strlcat(temp, namep, sizeof(temp));
  1772. }
  1773. else // lp just filename
  1774. snprintf(temp, sizeof(temp), "%s/%s", directory_, namep);
  1775. }
  1776. else if (namep[0] != '/' && !strchr(namep, ':')) // rem'd == 0
  1777. { // Relative path
  1778. if (directory_[0]) // Add filename
  1779. snprintf(temp, sizeof(temp), "%s/%s", directory_, namep);
  1780. else {
  1781. dirp = getcwd(dir, sizeof(dir)); // getcwd can fail and return wrong dir, bug?
  1782. snprintf(temp, sizeof(temp), "%s/%s", dir, namep); // No end '/' char from getcwd
  1783. }
  1784. }
  1785. else // Use lp
  1786. strlcpy(temp, namep, sizeof(temp));
  1787. if (d->ispath) { // path is used
  1788. strlcpy(temp, d->path, sizeof(temp)); // ?
  1789. if (namep[0] == '/' || namep[1] == ':' || // absolute or remote
  1790. !strncmp(namep, "ftp:", 4) || !strncmp(namep, "http:", 5) ||
  1791. !strncmp(namep, "https:", 6) || !strncmp(namep, "ipp:", 4) ||
  1792. !strncmp(namep, "mailto:", 7) || !strncmp(namep, "news:", 5))
  1793. strlcpy(temp, namep, sizeof(temp));
  1794. else if (!strncasecmp(namep, "javascript:history", 18)) {
  1795. strlcpy(temp, namep, sizeof(temp));
  1796. if (!(d->nstyle & HV_NONAVIGATE)) { // user navigation
  1797. strlcpy(temp, d->lpath, sizeof(temp)); // use last path
  1798. if (!d->lpath[0]) // last path empty
  1799. strlcpy(temp, d->path, sizeof(temp)); // use path
  1800. d->isnav = 1; // set is nav link
  1801. }
  1802. }
  1803. else if ((tptr = strrchr(temp, '/'))) // relative path, add filename
  1804. strlcpy(tptr + 1, namep, sizeof(temp)-(tptr + 1 - temp));
  1805. }
  1806. if (target[0]) { // Add target
  1807. strlcat(temp, "#", sizeof(temp)); // was snprintf(temp + strlen..
  1808. strlcat(temp, target, sizeof(temp));
  1809. }
  1810. while ((tptr = strstr(temp, "/.."))) { // remove ../ from path
  1811. for (sptr = tptr - 1; sptr > temp; sptr --)
  1812. if (*sptr == '/') break; // seek back to last dir
  1813. if (sptr == temp) break; // nothing to remove
  1814. *sptr = '\0'; // nul-terminate
  1815. strlcat(temp, tptr + 3, sizeof(temp)); // add rest of path
  1816. }
  1817. while ((tptr = strstr(temp, "/./"))) { // remove ./ from path
  1818. *tptr = '\0';
  1819. strlcat(temp, tptr + 2, sizeof(temp));
  1820. }
  1821. if (d->ispath) { // path is used
  1822. if (!strncasecmp(temp, "javascript:history", 18)) { // store js
  1823. strlcpy(d->lpath, d->path, sizeof(d->lpath)); // last path
  1824. strlcpy(d->path, temp, sizeof(d->path)); // link for history
  1825. }
  1826. else if ((tptr = strrchr(temp, '/'))) { // store valid ext
  1827. if (strstr(tptr, ".htm") || strstr(tptr, ".txt")) {
  1828. strlcpy(d->lpath, d->path, sizeof(d->lpath)); // last path
  1829. strlcpy(d->path, temp, sizeof(d->path)); // link for history
  1830. }
  1831. }
  1832. }
  1833. //printf(" follow_link d->path=(%s)\n",d->path);
  1834. //printf(" follow_link temp=(%s)\n",temp);
  1835. load(temp); // Load filename
  1836. }
  1837. else if (target[0]) // Target in link
  1838. {
  1839. if (d->ispath) { // path is used
  1840. if ((tptr = strrchr(d->path, '#'))) *tptr = '\0'; // remove target
  1841. strlcat(d->path, "#", sizeof(d->path));
  1842. strlcat(d->path, target, sizeof(d->path));
  1843. load(d->path); // load target for history
  1844. } else topline(target); // rem'd
  1845. }
  1846. //else topline(0); leftline(0); // rem'd
  1847. /*printf("\nFl_Help_Target\n");
  1848. printf(" targets=%s\n",d->targets->filename);
  1849. printf(" linkp=%s\n",d->linkp->filename);
  1850. printf(" ispush=%d\n",d->ispush);
  1851. printf(" islink=%d\n",d->islink);
  1852. printf(" resized=%d\n",d->resized);
  1853. printf(" ispath=%d\n",d->ispath);
  1854. printf(" nstyle=%d\n",d->nstyle);
  1855. printf(" top=%d\n",d->top);
  1856. printf(" ltop=%d\n",d->ltop);
  1857. printf(" isnav=%d\n",d->isnav);
  1858. printf(" rwidth=%d\n",d->rwidth);
  1859. printf(" rtime=%d\n",d->rtime);
  1860. printf(" rsec=%d\n",d->rsec);
  1861. printf(" rmil=%d\n",d->rmil);
  1862. printf(" path=%s\n",d->path);
  1863. printf(" lpath=%s\n",d->lpath);*/
  1864. if(link_to_free) free(link_to_free);
  1865. } // Fl_Help_View::follow_link()
  1866. //
  1867. // Fl_Help_View::font_face() - Get a font face from a list of names.
  1868. //
  1869. // Usage: parses a comma-separated string of font names in order of
  1870. // preference and returns the font face.
  1871. int // O - font face or base font list index
  1872. Fl_Help_View::font_face(const char *sp) // I - name of font to find
  1873. {
  1874. char buf[100],
  1875. namebuf[100]; // buffers
  1876. const char *listp,
  1877. *namep; // pointers
  1878. int ti = 0,
  1879. tj = 0,
  1880. tk = 0, // temp loop vars
  1881. tnum = 0,
  1882. lnum = 0,
  1883. fnum = 0, // temp/last/font counters
  1884. nfonts = 0,
  1885. nfaces = 0, // numbers
  1886. temp = 0,
  1887. slen = 0,
  1888. dfont = 0; // misc
  1889. unsigned char flen[10]; // font name lengths
  1890. slen = strlen(sp); // string length
  1891. if (!slen) return 0; // sp not valid
  1892. if (slen > 255) slen = 255; // set max length
  1893. for (ti = 0, listp = sp, nfaces = 0; ti < slen; ti ++, listp ++) {
  1894. if (ti == slen - 1 || *listp == ',') { // end or ',' char
  1895. if (nfaces < 8 && *(listp + 1) != ',') { // skip ",,"
  1896. flen[nfaces] = ti; // store positions
  1897. if (ti == slen - 1) flen[nfaces] = ti + 1;
  1898. nfaces ++; // count faces
  1899. }
  1900. }
  1901. }
  1902. for (ti = nfaces - 1; ti > 0; ti --) { // calc string lengths
  1903. temp = flen[ti] - flen[ti - 1] - 1;
  1904. flen[ti] = temp;
  1905. }
  1906. nfonts = Fl::set_fonts(0); // get ISO8859-1 fonts, ignore rest
  1907. for (ti = 0, listp = sp; ti < nfaces; ti ++) // main loop
  1908. {
  1909. while (*listp == ',') listp ++; // skip ',' chars
  1910. if (flen[ti] > sizeof(buf)-1) flen[ti] = sizeof(buf)-1; // max buffer size
  1911. for (tj = 0, tk = 0; tj < flen[ti]; tj ++) { // remove spaces in font names
  1912. if (isspace(listp[tj])) continue;
  1913. else if (listp[tj] == '-') break;
  1914. buf[tk] = tolower(listp[tj]); // copy char to lowercase
  1915. tk ++;
  1916. }
  1917. buf[tj] = '\0'; // nul-terminate
  1918. fnum = (uchar)*buf - 97; // first letter index, a = 0
  1919. if (fnum < 0 || fnum > 25) continue; // not a..z, assume font starts with letter
  1920. tnum = flet_[fnum]; // current face index, loop start
  1921. for (tj = fnum + 1; tj < 27; tj ++) {
  1922. if (flet_[tj] > 0) {
  1923. lnum = flet_[tj]; break; // last face index, loop end
  1924. }
  1925. }
  1926. slen = strlen(buf); // first word length
  1927. for (tj = tnum; tj < lnum; tj ++) { // find current font
  1928. fnum = face_[tj][0]; // base font index
  1929. namep = Fl::get_font_name((Fl_Font)fnum, &temp); // fltk font name
  1930. for (tk = 0, temp = 0; namep[tk] != '\0'; tk ++) { // remove spaces in font name
  1931. if (isspace(namep[tk])) continue;
  1932. else if (namep[tk] == '-') break;
  1933. namebuf[temp] = tolower(namep[tk]); // copy chars to lowercase
  1934. temp ++;
  1935. }
  1936. namebuf[tk] = '\0'; // nul-terminate
  1937. if (!strncmp(namebuf, buf, slen)) // found name
  1938. return fnum;
  1939. }
  1940. if (!dfont) { // check default fonts
  1941. if (!strncmp(buf, "courier", 7)) dfont = monofont_;
  1942. if (!strncmp(buf, "times", 5)) dfont = serifont_;
  1943. if (!strncmp(buf, "helvetica", 9)) dfont = sansfont_;
  1944. }
  1945. }
  1946. return dfont;
  1947. } // Fl_Help_View::font_face()
  1948. //
  1949. // Fl_Help_View::font_style() - Get a font style from a font list index.
  1950. //
  1951. // Usage: the font style argument takes the values:
  1952. // medium as 0, bold as 1, italic as 2, plus as 3.
  1953. int // O - font list index
  1954. Fl_Help_View::font_style(int fi, // I - font list index
  1955. unsigned char fs) // I - font style 0..3
  1956. {
  1957. int ti = 0; // temp loop var
  1958. if (fs > 3 || fi >= (int)sizeof(fref_)) return 0; // avoid crash
  1959. for (ti = 0; ti <= 3; ti ++) // find style
  1960. if (fi == face_[fref_[fi]][ti]) break;
  1961. ti |= fs; // combine bits
  1962. return face_[fref_[fi]][ti];
  1963. } // Fl_Help_View::font_style()
  1964. //
  1965. // Fl_Help_View::format() - Format the help text.
  1966. //
  1967. void Fl_Help_View::format()
  1968. {
  1969. char *sp, // Pointer into buffer
  1970. *tp, // temp char pointer
  1971. *ap, // attribute pointer
  1972. buf[1024], // Text buffer
  1973. attr[1024], // Attribute buffer
  1974. wattr[1024], // Width attribute buffer
  1975. hattr[1024], // Height attribute buffer
  1976. linkdest[1024], // Link destination
  1977. tcss[1024], // temp css
  1978. tchar[1024], // temp char buffer
  1979. csstag[255], // css tag buffer
  1980. tag[4]; // tag/element 4-char buf
  1981. const char *ptr, // Pointer into block
  1982. *attrptr, // Start of attributes ptr
  1983. *tagptr; // Start of tag/element ptr
  1984. int ti = 0,
  1985. tj = 0, // Temp loop var
  1986. done = 0, // Are we done yet?
  1987. row = 0, // Current table row (block number)
  1988. talign = 0, // Current alignment
  1989. newalign = 0, // New alignment
  1990. head = 0, // Head/body section flag
  1991. needspace = 0, // Do we need whitespace?
  1992. table_width = 0, // Width of table
  1993. table_offset = 0, // Offset of table
  1994. column = 0, // Current table column number
  1995. line = 0, // Current line in block
  1996. links = 0, // Links for current line
  1997. trpop = 0, // tr popped flag
  1998. pflag = 0, // p flag
  1999. brflag = 0, // br flag
  2000. liflag = 0, // li flag
  2001. listnest = 0, // list nest
  2002. tdline = 0, // td line
  2003. colspan = 0, // COLSPAN attribute
  2004. qch = 0, // Quote char
  2005. dx = 0,
  2006. dy = 0, // Boxtype position offsets
  2007. dw = 0,
  2008. dh = 0, // Boxtype sizes
  2009. ss = 0, // Scrollbar size
  2010. temph = 0,
  2011. tempw = 0, // Temp scrollbar sizes
  2012. tempx = 0,
  2013. tempy = 0, // temp positions
  2014. linew = 0, // current line width
  2015. imgw = 0, // Image width
  2016. imgh = 0, // Image height
  2017. hwidth = 0, // horizontal window width
  2018. ulnest = 0, // ul nest type
  2019. ntables = 0, // number of nested tables
  2020. fonty = 0;
  2021. int columns[HV_64], // Column widths
  2022. cells[HV_64], // Cells in the current row
  2023. tcolumns[HV_64][HV_16], // nested table column widths
  2024. tcells[HV_64][HV_16], // nested table cell blocks
  2025. rowdata[3][HV_16], // row data - row,column,block
  2026. tfonts[HV_16 + 1], // table fonts - d->nfonts
  2027. ultype[HV_16]; // ul type array, 10 nesting levels should do
  2028. unsigned char thsize,
  2029. tfsize; // font sizes
  2030. fl_margins margins(default_margin_); // Left margin stack
  2031. Fl_Help_Block *block, // Current block
  2032. *cell, // Current table cell
  2033. b, // current block object
  2034. *tempb = 0; // temp block
  2035. //*cssb = 0; // current css block - not used
  2036. Fl_Color tclr,
  2037. rclr, // Table/row background color
  2038. tbclr[2][HV_16]; // nested table/tr bgcolor
  2039. Fl_Boxtype bt = (box()) ? box() : FL_DOWN_BOX; // Box to draw
  2040. Fl_Shared_Image *img = 0; // Shared image - rem'd NULL
  2041. // zero arrays
  2042. memset(columns, 0, sizeof(columns));
  2043. memset(cells, 0, sizeof(cells));
  2044. memset(rowdata, 0, sizeof(rowdata));
  2045. memset(tcolumns, 0, sizeof(tcolumns));
  2046. memset(tcells, 0, sizeof(tcells));
  2047. memset(tfonts, 0, sizeof(tfonts));
  2048. memset(ultype, 0, sizeof(ultype));
  2049. memset(tbclr, 0, sizeof(tbclr));
  2050. // Reset document width
  2051. ss = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size();
  2052. hsize_ = w() - ss - Fl::box_dw(bt);
  2053. hwidth = hsize_; // used in add_block instead of hsize_
  2054. //printf("\n FORMAT\n%s",value_);
  2055. done = 0;
  2056. while (!done)
  2057. {
  2058. // Reset state variables
  2059. done = 1;
  2060. nblocks_ = 0;
  2061. nlinks_ = 0;
  2062. ntargets_ = 0;
  2063. size_ = 0;
  2064. bgcolor_ = color();
  2065. textcolor_ = textcolor();
  2066. linkcolor_ = fl_contrast(FL_BLUE, color());
  2067. tclr = rclr = bgcolor_;
  2068. for (ti = 0; ti < HV_16; ti ++)
  2069. tbclr[0][ti] = tbclr[1][ti] = bgcolor_;
  2070. strcpy(title_, "Untitled");
  2071. if (!value_) return;
  2072. // Setup for formatting
  2073. initfont(b.font, b.fsize);
  2074. line = 0;
  2075. links = 0;
  2076. column = 0;
  2077. b.x = margins.clear();
  2078. b.y = b.fsize + 2;
  2079. b.w = 0;
  2080. b.h = 0;
  2081. b.border = 0;
  2082. b.border_color = FL_BLACK;
  2083. b.pre = 0;
  2084. b.tag = 0;
  2085. b.bgcolor = bgcolor_;
  2086. block = add_block(b, value_, hwidth);
  2087. row = 0;
  2088. head = 0;
  2089. talign = LEFT;
  2090. newalign = LEFT;
  2091. needspace = 0;
  2092. linkdest[0] = '\0';
  2093. table_offset = 0;
  2094. trpop = 0;
  2095. pflag = 1;
  2096. brflag = 0;
  2097. liflag = 0;
  2098. listnest = 0;
  2099. ulnest = 0;
  2100. thsize = 0;
  2101. tfsize = 0;
  2102. ntables = -1;
  2103. tdline = 0;
  2104. linew = 0;
  2105. for (ptr = value_, sp = buf; *ptr; ) // Parse from value_
  2106. {
  2107. if ((*ptr == '<' || isspace((*ptr) & 255)) && sp > buf)
  2108. {
  2109. *sp = '\0'; // Nul-terminate
  2110. b.w = (int)fl_width(buf); // Get width
  2111. if (!head && !b.pre) // Normal text
  2112. {
  2113. if (b.w > hsize_) { // Reformat
  2114. hsize_ = b.w;
  2115. done = 0; // rem'd break; in all reformat checks, not needed
  2116. }
  2117. if (needspace && b.x > block->x)
  2118. b.w += (int)fl_width(" ");
  2119. // no new line if word too long and no word before it
  2120. if (!(b.x < 7 && b.w > block->w) && (b.x + b.w > block->w)) {
  2121. block->end = ptr - strlen(buf); // end line on last word
  2122. line = do_align(block, 0, b.x, newalign, links);
  2123. b.x = block->x;
  2124. block->h += b.h;
  2125. b.y += b.h; //b.y = block->y + block->h;
  2126. b.h = 0;
  2127. line = 0;
  2128. block = add_block(b, ptr - strlen(buf), (row) ? block->w : hwidth);
  2129. }
  2130. if (linkdest[0])
  2131. add_link(linkdest, b.x, b.y - b.fsize, b.w, b.fsize);
  2132. b.x += b.w;
  2133. if (b.fsize + 2 > b.h) b.h = b.fsize + 2; // Set b.h
  2134. needspace = 0;
  2135. }
  2136. else if (!head && b.pre) // Pre text
  2137. {
  2138. if (linkdest[0]) // Add a link as needed
  2139. add_link(linkdest, b.x, b.y - b.h, b.w, b.h);
  2140. b.x += b.w;
  2141. linew += b.w;
  2142. if (b.fsize + 2 > b.h) b.h = b.fsize + 2; // Set b.h
  2143. while (isspace((*ptr) & 255)) // ' ' '\t'\n'\v'\f'\r' chars
  2144. {
  2145. if (*ptr == '\n') { // '\n' char
  2146. if (b.x > hsize_) break;
  2147. block->end = ptr;
  2148. line = do_align(block, 0, b.x, newalign, links);
  2149. b.x = block->x;
  2150. block->h += b.h;
  2151. b.y += b.h; //b.y = block->y + block->h;
  2152. b.h = 0;
  2153. line = 0;
  2154. linew = 0;
  2155. block = add_block(b, ptr, (row) ? block->w : hwidth);
  2156. //b.h = b.fsize + 2; // Set b.h
  2157. }
  2158. else if (*ptr == '\t') {
  2159. ti = linew / (int)fl_width(" "); // number of chars, monospace
  2160. tempw = 8 - (ti & 7); // number of tabs 1..8
  2161. b.x += tempw * (int)fl_width(" "); // pre tabs width fix
  2162. linew += tempw * (int)fl_width(" ");
  2163. }
  2164. else {
  2165. b.x += (int)fl_width(" ");
  2166. linew += (int)fl_width(" ");
  2167. }
  2168. if (b.fsize + 2 > b.h) b.h = b.fsize + 2; // Set b.h
  2169. ptr ++;
  2170. }
  2171. if (b.x > hsize_) { // Reformat
  2172. hsize_ = b.x + 4;
  2173. done = 0;
  2174. }
  2175. needspace = 0;
  2176. }
  2177. else // Handle normal text or stuff in the <HEAD> section
  2178. {
  2179. while (isspace((*ptr) & 255)) ptr ++;
  2180. }
  2181. //printf("b->line=%d b.x=%d b.w=%d b->x=%d b->w=%d b->y=%d b->h=%d b.y=%d b.h=%d buf=%s\n",
  2182. // block->line, b.x, b.w, block->x, block->w, block->y, block->h, b.y, b.h, buf);
  2183. pflag = 0; // reset flags
  2184. brflag = 0;
  2185. sp = buf;
  2186. }
  2187. if (*ptr == '<')
  2188. {
  2189. tagptr = ptr; // Start of tag
  2190. ptr ++;
  2191. if (!strncmp(ptr, "!--", 3)) { // Found "!--"
  2192. ptr += 3;
  2193. if ((ptr = strstr(ptr, "-->"))) { // Skip comment - rem'd != 0
  2194. ptr += 3;
  2195. continue;
  2196. }
  2197. else
  2198. break;
  2199. }
  2200. while (*ptr && *ptr != '>' && !isspace((*ptr) & 255))
  2201. if (sp < (buf + sizeof(buf) - 1))
  2202. *(sp ++) = *(ptr ++); // added ()
  2203. else
  2204. ptr ++;
  2205. *sp = '\0'; // Nul-terminate
  2206. sp = buf;
  2207. // puts(buf);
  2208. attrptr = ptr; // Start of attributes
  2209. while (*ptr && *ptr != '>') ptr ++;
  2210. if (*ptr == '>') ptr ++;
  2211. b.tag = strlen(buf); // store strlen
  2212. for (ti = 0; ti < b.tag; ti ++) // set css class tag
  2213. csstag[ti] = buf[ti];
  2214. csstag[ti] = '\0'; // nul-terminate
  2215. if (get_attr(attrptr, "CLASS", tchar, sizeof(tchar))) {
  2216. strlcat(csstag, ".", sizeof(csstag));
  2217. strlcat(csstag, tchar, sizeof(csstag));
  2218. }
  2219. if (b.tag > 4) b.tag = 4; // limit
  2220. for (ti = 0; ti < b.tag; ti ++) // set abbreviate tag, uppercase
  2221. tag[ti] = toupper(buf[ti]);
  2222. for (ti = b.tag; ti < 4; ti ++) // set chars after to nul
  2223. tag[ti] = 0;
  2224. if (buf[0] != '/' && b.tag > 3) tag[3] = 0; // eg. HTML=HTM
  2225. b.tag = CMD(tag[0],tag[1],tag[2],tag[3]); // tag fourcc int
  2226. //printf("buf=%s len=%d tag=%c%c%c%c, \n",
  2227. // buf,strlen(buf),tag[0],tag[1],tag[2],tag[3]);
  2228. // End of command reached
  2229. if (b.tag == CMD('A',0,0,0)) // 'A'
  2230. {
  2231. if (get_attr(attrptr, "NAME", attr, sizeof(attr)))
  2232. add_target(attr, b.y - b.fsize - 2);
  2233. if (get_attr(attrptr, "HREF", attr, sizeof(attr)))
  2234. strlcpy(linkdest, attr, sizeof(linkdest));
  2235. }
  2236. else if (b.tag == CMD('/','A',0,0)) // '/A'
  2237. {
  2238. linkdest[0] = '\0';
  2239. }
  2240. else if (b.tag == CMD('B',0,0,0) ||
  2241. b.tag == CMD('S','T','R',0)) // 'B' 'STRONG'
  2242. {
  2243. b.font = font_style(b.font, FL_BOLD);
  2244. pushfont(b.font, b.fsize);
  2245. }
  2246. else if (b.tag == CMD('/','B',0,0) ||
  2247. b.tag == CMD('/','S','T','R')) // '/B' '/STRONG'
  2248. {
  2249. popfont(b.font, b.fsize);
  2250. }
  2251. else if (b.tag == CMD('B','L','O',0) ||
  2252. b.tag == CMD('D','L',0,0) ||
  2253. b.tag == CMD('U','L',0,0) ||
  2254. b.tag == CMD('O','L',0,0) ||
  2255. b.tag == CMD('D','D',0,0) ||
  2256. b.tag == CMD('D','T',0,0)) // 'BLOCKQUOTE' 'DL'OL'UL'
  2257. {
  2258. // todo: dd and dt need their own section, similar to li
  2259. block->end = tagptr;
  2260. line = do_align(block, line, b.x, newalign, links);
  2261. b.x = block->x;
  2262. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2263. block->h += b.h;
  2264. b.y = block->y + block->h;
  2265. newalign = LEFT;
  2266. if (b.tag == CMD('U','L',0,0)) { // ul
  2267. ulnest ++; // inc ul nest type
  2268. if (ulnest < 10) {
  2269. get_attr(attrptr, "TYPE", attr, sizeof(attr)); // bullet types
  2270. if (!strncasecmp(attr, "disc", 4) ||
  2271. !strncasecmp(attr, "disk", 4))
  2272. ultype[ulnest] = 1;
  2273. else if (!strncasecmp(attr, "circle", 6))
  2274. ultype[ulnest] = 2;
  2275. else if (!strncasecmp(attr, "square", 6))
  2276. ultype[ulnest] = 3;
  2277. }
  2278. }
  2279. if (b.tag == CMD('B','L','O',0) ||
  2280. b.tag == CMD('D','L',0,0) ||
  2281. b.tag == CMD('O','L',0,0) ||
  2282. b.tag == CMD('U','L',0,0)) { // blockquote, dl, ol, ul
  2283. b.x = margins.push(40); // changed 4 * b.fsize
  2284. if (!pflag && !listnest) {
  2285. b.y += fontsize_ + 2; block->h += fontsize_ + 2; pflag = 1;
  2286. }
  2287. listnest ++; // inc list nest
  2288. }
  2289. block = add_block(b, tagptr, (row) ? block->w : hwidth);
  2290. b.h = 0;
  2291. needspace = 0;
  2292. line = 0;
  2293. newalign = get_align(attrptr, talign);
  2294. }
  2295. else if (b.tag == CMD('/','B','L','O') ||
  2296. b.tag == CMD('/','D','L',0) ||
  2297. b.tag == CMD('/','O','L',0) ||
  2298. b.tag == CMD('/','U','L',0)) // '/BLOCKQUOTE' '/DL'/OL'/UL'
  2299. {
  2300. line = do_align(block, line, b.x, newalign, links);
  2301. block->end = ptr;
  2302. b.x = block->x;
  2303. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2304. block->h += b.h;
  2305. b.y += b.h;
  2306. if (b.tag == CMD('/','U','L',0)) { // /ul
  2307. if (ulnest < 9) ultype[ulnest] = 0; // reset ul type
  2308. if (ulnest > 0) ulnest --; // dec ul nest type
  2309. }
  2310. if (listnest > 0) listnest --; // dec list nest
  2311. if (!pflag && !listnest) {
  2312. b.y += fontsize_ + 2; block->h += fontsize_ + 2; pflag = 1;
  2313. }
  2314. b.x = margins.pop();
  2315. while (isspace((*ptr) & 255)) ptr ++;
  2316. block = add_block(b, ptr, (row) ? block->w : hwidth);
  2317. b.h = 0;
  2318. needspace = 0;
  2319. line = 0;
  2320. newalign = talign;
  2321. }
  2322. else if (b.tag == CMD('B','O','D',0)) // 'BODY'
  2323. {
  2324. if (get_attr(attrptr, "BGCOLOR", attr, sizeof(attr)))
  2325. b.bgcolor = bgcolor_ = get_color(attr, color());
  2326. if (get_attr(attrptr, "TEXT", attr, sizeof(attr)))
  2327. textcolor_ = get_color(attr, textcolor());
  2328. if (get_attr(attrptr, "LINK", attr, sizeof(attr)))
  2329. linkcolor_ = get_color(attr, fl_contrast(FL_BLUE, color()));
  2330. parse_css(b, csstag, tchar);
  2331. if (b.fsize < fontsize_) b.fsize = fontsize_; // force min size
  2332. pushfont(b.font, b.fsize);
  2333. serifont_ = b.font; // body overrides default font but not size
  2334. }
  2335. else if (b.tag == CMD('B','R',0,0)) // 'BR'
  2336. {
  2337. block->end = tagptr;
  2338. line = do_align(block, 0, b.x, newalign, links);
  2339. b.x = block->x;
  2340. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2341. if (brflag) b.h = b.fsize + 2; // set b.h
  2342. block->h += b.h;
  2343. b.y = block->y + block->h; //b.y += b.h;
  2344. brflag = 1;
  2345. block = add_block(b, tagptr, (row) ? block->w : hwidth);
  2346. b.h = 0;
  2347. needspace = 0;
  2348. line = 0;
  2349. }
  2350. else if (b.tag == CMD('C','E','N',0)) // 'CENTER'
  2351. {
  2352. block->end = tagptr;
  2353. line = do_align(block, line, b.x, newalign, links);
  2354. b.x = block->x;
  2355. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2356. block->h += b.h;
  2357. b.y = block->y + block->h;
  2358. newalign = CENTER;
  2359. block = add_block(b, tagptr, (row) ? block->w : hwidth);
  2360. b.h = 0;
  2361. needspace = 0;
  2362. line = 0;
  2363. newalign = talign = CENTER;
  2364. }
  2365. else if (b.tag == CMD('/','C','E','N')) // '/CENTER'
  2366. {
  2367. line = do_align(block, line, b.x, newalign, links);
  2368. block->end = ptr;
  2369. b.x = block->x;
  2370. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2371. block->h += b.h;
  2372. b.y += b.h;
  2373. talign = LEFT;
  2374. while (isspace((*ptr) & 255)) ptr ++;
  2375. block = add_block(b, ptr, (row) ? block->w : hwidth);
  2376. b.h = 0;
  2377. needspace = 0;
  2378. line = 0;
  2379. newalign = talign;
  2380. }
  2381. else if (b.tag == CMD('C','O','D',0) ||
  2382. b.tag == CMD('T','T',0,0)) // 'CODE' 'TT'
  2383. {
  2384. b.font = monofont_;
  2385. pushfont(b.font, b.fsize);
  2386. }
  2387. else if (b.tag == CMD('/','C','O','D') ||
  2388. b.tag == CMD('/','T','T',0)) // '/CODE' '/TT'
  2389. {
  2390. popfont(b.font, b.fsize);
  2391. }
  2392. else if (b.tag == CMD('D','I','V',0)) // 'DIV'
  2393. {
  2394. if (get_attr(attrptr, "ID", attr, sizeof(attr)))
  2395. add_target(attr, b.y - b.fsize - 2);
  2396. block->end = tagptr;
  2397. line = do_align(block, line, b.x, newalign, links);
  2398. b.x = block->x;
  2399. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2400. block->h += b.h;
  2401. b.y = block->y + block->h;
  2402. newalign = LEFT;
  2403. if (!pflag) {
  2404. b.y += fontsize_ + 2; block->h += fontsize_ + 2; pflag = 1;
  2405. }
  2406. block = add_block(b, tagptr, (row) ? block->w : hwidth);
  2407. b.h = 0;
  2408. needspace = 0;
  2409. line = 0;
  2410. newalign = get_align(attrptr, talign);
  2411. }
  2412. else if (b.tag == CMD('/','D','I','V')) // '/DIV'
  2413. {
  2414. line = do_align(block, line, b.x, newalign, links);
  2415. block->end = ptr;
  2416. b.x = block->x;
  2417. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2418. block->h += b.h;
  2419. b.y += b.h;
  2420. talign = LEFT;
  2421. while (isspace((*ptr) & 255)) ptr ++;
  2422. block = add_block(b, ptr, (row) ? block->w : hwidth);
  2423. b.h = 0;
  2424. needspace = 0;
  2425. line = 0;
  2426. newalign = talign;
  2427. }
  2428. else if (b.tag == CMD('F','O','N',0)) // 'FONT'
  2429. {
  2430. if (get_attr(attrptr, "FACE", attr, sizeof(attr)))
  2431. b.font = font_face(attr);
  2432. tfsize = b.fsize; // store b.fsize
  2433. if (get_attr(attrptr, "SIZE", attr, sizeof(attr))) {
  2434. if (isdigit(attr[0])) // Absolute size
  2435. b.fsize = (int)(fontsize_ * pow(1.2, atoi(attr) - 3.0));
  2436. else // Relative size
  2437. b.fsize = (int)(b.fsize * pow(1.2, atoi(attr)));
  2438. }
  2439. pushfont(b.font, b.fsize);
  2440. //if (fonty != b.y && !block->maxh) {
  2441. //block->liney = abs(b.fsize - tfsize);
  2442. //b.h = b.fsize + 2; // set b.h
  2443. //}
  2444. fonty = b.y; // set font y
  2445. }
  2446. else if (b.tag == CMD('/','F','O','N')) // '/FONT'
  2447. {
  2448. tfsize = b.fsize; // store b.fsize
  2449. popfont(b.font, b.fsize);
  2450. //if (fonty != b.y && !block->maxh) {
  2451. //block->liney = abs(b.fsize - tfsize);
  2452. //b.h = b.fsize + 2; // set b.h
  2453. //}
  2454. fonty = b.y; // set font y
  2455. }
  2456. else if (tag[0] == 'H' && isdigit(tag[1])) // 'H1'
  2457. {
  2458. if (tag[1] < '7') { // ignore if > 6
  2459. block->end = tagptr;
  2460. line = do_align(block, line, b.x, newalign, links);
  2461. b.x = block->x;
  2462. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2463. block->h += b.h;
  2464. b.y = block->y + block->h;
  2465. newalign = LEFT;
  2466. //Added target
  2467. if (get_attr(attrptr, "ID", attr, sizeof(attr)))
  2468. add_target(attr, b.y - b.fsize - 2);
  2469. thsize = b.fsize; // store b.fsize
  2470. b.font = font_style(b.font, FL_BOLD);
  2471. switch (tag[1]) { // header sizes
  2472. case '1' : b.fsize = 24; break;
  2473. case '2' : b.fsize = 18; break;
  2474. case '3' : b.fsize = 16; break;
  2475. case '4' : b.fsize = 14; break;
  2476. case '5' : b.fsize = 12; break;
  2477. case '6' : b.fsize = 10; break;
  2478. }
  2479. pushfont(b.font, b.fsize);
  2480. if (!pflag) {
  2481. b.y += fontsize_ + 2; block->h += fontsize_ + 2; pflag = 1;
  2482. }
  2483. b.y += b.fsize - thsize + (thsize / 4); // add offset
  2484. block->h += b.fsize - thsize + (thsize / 4);
  2485. block = add_block(b, tagptr, (row) ? block->w : hwidth);
  2486. b.h = 0;
  2487. needspace = 0;
  2488. line = 0;
  2489. newalign = get_align(attrptr, talign);
  2490. }
  2491. }
  2492. else if (b.tag == CMD('/','H',tag[2],0) && isdigit(tag[2])) // '/H1'
  2493. {
  2494. if (tag[2] < '7') { // ignore if > 6
  2495. line = do_align(block, line, b.x, newalign, links);
  2496. block->end = ptr;
  2497. b.x = block->x;
  2498. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2499. block->h += b.h;
  2500. b.y += b.h;
  2501. if (!pflag) {
  2502. b.y += fontsize_ + 2; block->h += fontsize_ + 2; pflag = 1;
  2503. }
  2504. b.y -= b.fsize - thsize;// + (thsize / 4); // sub offset
  2505. block->h -= b.fsize - thsize;// + (thsize / 4);
  2506. popfont(b.font, b.fsize);
  2507. while (isspace((*ptr) & 255)) ptr ++;
  2508. block = add_block(b, ptr, (row) ? block->w : hwidth);
  2509. b.h = 0;
  2510. needspace = 0;
  2511. line = 0;
  2512. newalign = talign;
  2513. }
  2514. }
  2515. else if (b.tag == CMD('H','E','A',0)) // 'HEAD'
  2516. {
  2517. head = 1;
  2518. }
  2519. else if (b.tag == CMD('/','H','E','A')) // '/HEAD'
  2520. {
  2521. head = 0;
  2522. }
  2523. else if (b.tag == CMD('H','R',0,0)) // 'HR'
  2524. {
  2525. block->end = tagptr;
  2526. line = do_align(block, line, b.x, newalign, links);
  2527. b.x = block->x;
  2528. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2529. if(get_attr ( attrptr, "VHEIGHT", attr, sizeof ( attr ) ))
  2530. {
  2531. block->h += atoi ( attr );;
  2532. } else {
  2533. block->h += b.h;
  2534. }
  2535. b.y = block->y + block->h;
  2536. newalign = LEFT;
  2537. if (!pflag) {
  2538. b.y += fontsize_ + 2; block->h += fontsize_ + 2; pflag = 1;
  2539. }
  2540. block = add_block(b, tagptr, (row) ? block->w : hwidth);
  2541. //block->y -= (b.fsize / 2); // hr line offset
  2542. //b.y += fontsize_ + 2; // end paragraph
  2543. //block->h += fontsize_ + 2;
  2544. //pflag = 1;
  2545. b.h = b.fsize + 2; // set b.h - rem: ??
  2546. b.h = 0;
  2547. needspace = 0;
  2548. line = 0;
  2549. newalign = get_align(attrptr, talign);
  2550. }
  2551. else if (b.tag == CMD('H','T','M',0)) // 'HTML'
  2552. {
  2553. }
  2554. else if (b.tag == CMD('I',0,0,0) ||
  2555. b.tag == CMD('E','M',0,0)) // 'I' 'EM'
  2556. {
  2557. b.font = font_style(b.font, FL_ITALIC);
  2558. pushfont(b.font, b.fsize);
  2559. }
  2560. else if (b.tag == CMD('/','I',0,0) ||
  2561. b.tag == CMD('/','E','M',0)) // '/I' '/EM'
  2562. {
  2563. popfont(b.font, b.fsize);
  2564. }
  2565. else if (b.tag == CMD('I','M','G',0)) // 'IMG'
  2566. {
  2567. imgw = imgh = 0; // reset
  2568. if (get_attr(attrptr, "WIDTH", wattr, sizeof(wattr)))
  2569. imgw = get_length(wattr);
  2570. if (get_attr(attrptr, "HEIGHT", hattr, sizeof(hattr)))
  2571. imgh = get_length(hattr);
  2572. img = 0; // rem'd NULL
  2573. if (get_attr(attrptr, "SRC", attr, sizeof(attr))) {
  2574. img = get_image(attr, imgw, imgh);
  2575. imgw = img->w();
  2576. imgh = img->h();
  2577. }
  2578. b.w = imgw;
  2579. if (b.w > hsize_) { // Reformat
  2580. hsize_ = b.w;
  2581. done = 0;
  2582. }
  2583. if (needspace && b.x > block->x)
  2584. b.w += (int)fl_width(" ");
  2585. if ((b.x + b.w) > block->w) {
  2586. block->end = tagptr;
  2587. line = do_align(block, line, b.x, newalign, links);
  2588. b.x = block->x;
  2589. block->h += b.h;
  2590. b.y = block->y + block->h; //b.y += b.h;
  2591. line = 0;
  2592. block = add_block(b, tagptr, (row) ? block->w : hwidth);
  2593. b.h = 0;
  2594. needspace = 0;
  2595. }
  2596. if (linkdest[0])
  2597. add_link(linkdest, b.x, b.y - imgh, b.w, imgh);
  2598. b.x += b.w;
  2599. if ((imgh + 2) > b.h) b.h = imgh + 2; // Set img b.h
  2600. needspace = 0;
  2601. if (imgh > block->maxh)
  2602. block->maxh = imgh; // max image height
  2603. block->imgy = b.y; // y position of image
  2604. pflag = 0; // reset p flag
  2605. brflag = 0;
  2606. }
  2607. else if (b.tag == CMD('K','B','D',0)) // 'KBD'
  2608. {
  2609. b.font = font_style(monofont_, FL_BOLD);
  2610. pushfont(b.font, b.fsize);
  2611. }
  2612. else if (b.tag == CMD('/','K','B','D')) // '/KBD'
  2613. {
  2614. popfont(b.font, b.fsize);
  2615. }
  2616. else if (b.tag == CMD('L','I',0,0)) // 'LI'
  2617. {
  2618. block->end = tagptr;
  2619. line = do_align(block, line, b.x, newalign, links);
  2620. b.x = block->x;
  2621. if (!liflag && !listnest) { // push li, if not nested
  2622. b.x = margins.push(b.fsize);
  2623. liflag = 1;
  2624. }
  2625. block->h += b.h;
  2626. b.y = block->y + block->h;
  2627. newalign = LEFT;
  2628. block = add_block(b, tagptr, (row) ? block->w : hwidth);
  2629. // li > ul > ul nest
  2630. if (ulnest > 9) // square if out of bounds
  2631. block->type = 3;
  2632. else if (ultype[ulnest]) // ul type
  2633. block->type = ultype[ulnest];
  2634. else if (ulnest > 1) // ul nest type
  2635. block->type = ulnest;
  2636. else // none or ul nest type disc/disk
  2637. block->type = 1;
  2638. b.h = 0;
  2639. needspace = 0;
  2640. line = 0;
  2641. newalign = get_align(attrptr, talign);
  2642. }
  2643. else if (b.tag == CMD('/','L','I',0)) // '/LI'
  2644. {
  2645. line = do_align(block, line, b.x, newalign, links);
  2646. block->end = ptr;
  2647. b.x = block->x;
  2648. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2649. block->h += b.h;
  2650. b.y += b.h;
  2651. while (isspace((*ptr) & 255)) ptr ++;
  2652. block = add_block(b, ptr, (row) ? block->w : hwidth);
  2653. b.h = 0;
  2654. needspace = 0;
  2655. line = 0;
  2656. newalign = talign;
  2657. }
  2658. else if (b.tag == CMD('L','I','N',0)) // 'LINK'
  2659. {
  2660. if (get_attr(attrptr, "HREF", tchar, sizeof(tchar)))
  2661. strlcpy(tcss, tchar, sizeof(tcss));
  2662. for (ti = 0; tcss[ti] != '\0'; ti ++) // replace '\' chars
  2663. if (tcss[ti] == '\\') tcss[ti] = '/';
  2664. if (tcss[0] == '/' || tcss[1] == ':') // absolute
  2665. strlcpy(tchar, tcss, sizeof(tchar));
  2666. else { // relative
  2667. if (d->ispath) { // path is used
  2668. strlcpy(tchar, d->path, sizeof(tchar));
  2669. if ((tp = strrchr(tchar, '/'))) // replace filename
  2670. strlcpy(tp + 1, tcss, sizeof(tchar)-(tp + 1 - tchar));
  2671. }
  2672. else { // use directory
  2673. strlcpy(tchar, directory_, sizeof(tchar));
  2674. if (tchar[strlen(tchar)-1] != '/')
  2675. strlcat(tchar, "/", sizeof(tchar)); // add '/' to dir
  2676. strlcat(tchar, tcss, sizeof(tchar));
  2677. }
  2678. }
  2679. while ((tp = strstr(tchar, "/.."))) { // remove ../ from path
  2680. for (ap = tp - 1; ap > tchar; ap --)
  2681. if (*ap == '/') break; // seek back to last dir
  2682. if (ap == tchar) break; // nothing to remove
  2683. *ap = '\0'; // nul-terminate
  2684. strlcat(tchar, tp + 3, sizeof(tchar)); // add rest of path
  2685. }
  2686. while ((tp = strstr(tchar, "/./"))) { // remove ./ from path
  2687. *tp = '\0';
  2688. strlcat(tchar, tp + 2, sizeof(tchar));
  2689. }
  2690. if ((tp = strrchr(tcss, '.'))) { // check valid ext
  2691. if (strstr(tp, ".css")) load_css(tchar);
  2692. }
  2693. tcss[0] = '\0'; // reset
  2694. }
  2695. else if (b.tag == CMD('N','O','S',0)) // 'NOSCRIPT'
  2696. { // we don't support scripting so we won't skip this
  2697. }
  2698. else if (b.tag == CMD('P',0,0,0)) // 'P'
  2699. { // && !b.pre fixme?
  2700. block->end = tagptr;
  2701. line = do_align(block, line, b.x, newalign, links);
  2702. b.x = block->x;
  2703. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2704. block->h += b.h;
  2705. b.y = block->y + block->h;
  2706. newalign = LEFT;
  2707. if (!pflag) {
  2708. b.y += fontsize_ + 2; block->h += fontsize_ + 2; pflag = 1;
  2709. }
  2710. block = add_block(b, tagptr, (row) ? block->w: hwidth);
  2711. b.h = 0;
  2712. needspace = 0;
  2713. line = 0;
  2714. newalign = get_align(attrptr, talign);
  2715. }
  2716. else if (b.tag == CMD('/','P',0,0)) // '/P'
  2717. {
  2718. line = do_align(block, line, b.x, newalign, links);
  2719. block->end = ptr;
  2720. b.x = block->x;
  2721. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2722. block->h += b.h;
  2723. b.y = block->y + block->h;
  2724. if (!pflag) {
  2725. b.y += fontsize_ + 2; block->h += fontsize_ + 2; pflag = 1;
  2726. }
  2727. while (isspace((*ptr) & 255)) ptr ++;
  2728. block = add_block(b, ptr, (row) ? block->w : hwidth);
  2729. b.h = 0;
  2730. needspace = 0;
  2731. line = 0;
  2732. newalign = talign;
  2733. }
  2734. else if (b.tag == CMD('P','R','E',0)) // 'PRE'
  2735. {
  2736. block->end = tagptr;
  2737. line = do_align(block, line, b.x, newalign, links);
  2738. b.x = block->x;
  2739. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2740. block->h += b.h;
  2741. b.y = block->y + block->h;
  2742. newalign = LEFT;
  2743. linew = 0;
  2744. b.pre = 1;
  2745. b.font = monofont_;
  2746. b.fsize = fontsize_;
  2747. parse_css(b, csstag, tchar);
  2748. pushfont(b.font, b.fsize);
  2749. if (!pflag) {
  2750. b.y += fontsize_ + 2; block->h += fontsize_ + 2; pflag = 1;
  2751. }
  2752. block = add_block(b, tagptr, (row) ? block->w : hwidth);
  2753. b.h = 0;
  2754. needspace = 0;
  2755. line = 0;
  2756. newalign = get_align(attrptr, talign);
  2757. }
  2758. else if (b.tag == CMD('/','P','R','E')) // '/PRE'
  2759. {
  2760. line = do_align(block, line, b.x, newalign, links);
  2761. block->end = ptr;
  2762. b.x = block->x;
  2763. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2764. block->h += b.h;
  2765. b.y += b.h;
  2766. for (ti = nblocks_ - 1, tj = 0; ti > 0; ti --) { // find start block index
  2767. tempb = blocks_ + ti;
  2768. if (tempb->tag == CMD('P','R','E',0)) tj = 1; // pre line
  2769. if (tj && tempb->tag != CMD('P','R','E',0)) {
  2770. tempb = blocks_ + ti + 1; // + 1 gets first pre
  2771. break;
  2772. }
  2773. }
  2774. tempb->h = block->y - tempb->y; // recalculate h
  2775. if (!pflag) {
  2776. b.y += fontsize_ + 2; block->h += fontsize_ + 2; pflag = 1; }
  2777. b.pre = 0;
  2778. popfont(b.font, b.fsize);
  2779. while (isspace((*ptr) & 255)) ptr ++;
  2780. block = add_block(b, ptr, (row) ? block->w : hwidth);
  2781. b.h = 0;
  2782. needspace = 0;
  2783. line = 0;
  2784. newalign = talign;
  2785. }
  2786. else if (b.tag == CMD('S','C','R',0)) // 'SCRIPT'
  2787. {
  2788. while (ptr) { // skip scripting
  2789. ptr = strstr(ptr, "</");
  2790. if (!strncasecmp(ptr, "</SCRIPT>", 9)) break;
  2791. }
  2792. if (ptr) { // found </script>
  2793. ptr += 9;
  2794. continue;
  2795. }
  2796. else // not found
  2797. break;
  2798. }
  2799. else if (b.tag == CMD('T','A','B',0)) // 'TABLE'
  2800. {
  2801. if (ntables >= 0) { // store row data
  2802. rowdata[0][ntables] = row; // row
  2803. rowdata[1][ntables] = column; // column
  2804. rowdata[2][ntables] = block - blocks_; // block number
  2805. tbclr[0][ntables] = tclr; // table bgcolor
  2806. tbclr[1][ntables] = rclr; // tr bgcolor
  2807. for (ti = 0; ti < HV_64; ti ++) {
  2808. tcolumns[ti][ntables] = columns[ti]; // cell columns
  2809. tcells[ti][ntables] = cells[ti]; // cell blocks
  2810. if (columns[ti] == 0) break;
  2811. }
  2812. }
  2813. if (ntables < HV_16) ntables ++; // max limit
  2814. tfonts[ntables] = d->nfonts; // number of fonts
  2815. block->end = tagptr;
  2816. line = do_align(block, line, b.x, newalign, links);
  2817. b.x = block->x;
  2818. block->h += b.h + 8; // add tr gap offset, wrong line gaps
  2819. b.y = block->y + block->h;
  2820. newalign = LEFT;
  2821. b.border = 0; // Reset
  2822. b.border_color = FL_BLACK; // Reset
  2823. if (get_attr(attrptr, "BORDER", attr, sizeof(attr)))
  2824. b.border = atoi(attr);
  2825. if (get_attr(attrptr, "BORDERCOLOR", attr, sizeof(attr)))
  2826. b.border_color = get_color(attr, FL_BLACK);
  2827. get_attr(attrptr, "BGCOLOR", attr, sizeof(attr));
  2828. tclr = rclr = get_color(attr, bgcolor_);
  2829. memset(columns, 0, sizeof(columns)); // zero for new table
  2830. format_table(table_width, columns, tagptr, b.x, 0);
  2831. if ((b.x + table_width) > hsize_) { // Reformat
  2832. //printf("\nb.x=%d, table_width=%d, hsize_=%d\n\n",
  2833. // b.x, table_width, hsize_);
  2834. hsize_ = b.x + table_width;
  2835. for (ti = 0; ti < HV_64; ti ++)
  2836. if (columns[ti] == 0) break; // num columns
  2837. hsize_ += 6 * ti; // add internal borders
  2838. done = 0;
  2839. }
  2840. switch (get_align(attrptr, talign)) {
  2841. default :
  2842. table_offset = 0; break;
  2843. case CENTER :
  2844. table_offset = ((hsize_ - table_width) / 2) - fontsize_; break;
  2845. case RIGHT :
  2846. table_offset = hsize_ - table_width - fontsize_ - default_margin_; break;
  2847. }
  2848. block = add_block(b, tagptr, (row) ? block->w : hwidth);
  2849. column = 0;
  2850. b.h = 0;
  2851. needspace = 0;
  2852. line = 0;
  2853. newalign = get_align(attrptr, talign);
  2854. }
  2855. else if (b.tag == CMD('/','T','A','B')) // '/TABLE'
  2856. {
  2857. if (row) { // no /tr
  2858. line = do_align(block, line, b.x, newalign, links);
  2859. if (tdline) { // td was popped
  2860. block->line = tdline; tdline = 0; } // last line in td
  2861. block->end = ptr;
  2862. block->h += b.h;
  2863. talign = LEFT;
  2864. if (b.h == 0) b.h = b.fsize + 2; // empty td on end of row
  2865. b.x = blocks_[row].x;
  2866. b.y = blocks_[row].y + blocks_[row].h;
  2867. for (cell = blocks_ + row + 1; cell <= block; cell ++)
  2868. if (cell->y + cell->h > b.y) b.y = cell->y + cell->h;
  2869. block = blocks_ + row; // current row block ptr
  2870. block->h = b.y - block->y + 2;
  2871. for (ti = 0; ti < column; ti ++)
  2872. if (cells[ti]) { // cell block exists
  2873. cell = blocks_ + cells[ti]; // get cell block ptr
  2874. cell->h = block->h;
  2875. }
  2876. b.y = block->y + block->h - 4; // tr gap offset between rows
  2877. block = add_block(b, ptr, hwidth);
  2878. needspace = 0;
  2879. row = 0; // reset row block number
  2880. line = 0;
  2881. }
  2882. line = do_align(block, line, b.x, newalign, links);
  2883. if (tdline) { block->line = tdline; tdline = 0; } // td popped
  2884. block->end = ptr;
  2885. b.x = block->x;
  2886. b.h = 0; // reset b.h
  2887. block->h += b.h; // may be needed if no /tr
  2888. b.y += b.h + 8; // add tr gap offset, wrong line gaps
  2889. if (!trpop) { b.x = margins.pop(); row = 0; } // pop tr indent
  2890. trpop = 0; // reset tr popped
  2891. b.x = margins.current();
  2892. while (isspace((*ptr) & 255)) ptr ++;
  2893. block = add_block(b, ptr, (row) ? block->w : hwidth);
  2894. b.h = 0;
  2895. needspace = 0;
  2896. line = 0;
  2897. newalign = talign;
  2898. d->nfonts = tfonts[ntables] + 1; // number of fonts + 1 for pop
  2899. popfont(b.font, b.fsize); // tables not popping last font fix
  2900. if (ntables >= 0) ntables --; // min limit
  2901. if (ntables >= 0) { // restore row data
  2902. row = rowdata[0][ntables]; // row
  2903. column = rowdata[1][ntables]; // column
  2904. cell = blocks_ + rowdata[2][ntables] + 1; // table block
  2905. b.x = block->x = cell->x; // nested table popping cell margin fix
  2906. block->w = cell->w;
  2907. tclr = tbclr[0][ntables]; // table bgcolor
  2908. rclr = tbclr[1][ntables]; // tr bgcolor
  2909. for (ti = 0; ti < HV_64; ti ++) {
  2910. columns[ti] = tcolumns[ti][ntables]; // cell columns
  2911. // nested table overwriting cell heights fix
  2912. cells[ti] = tcells[ti][ntables]; // cell blocks
  2913. if (tcolumns[ti][ntables] == 0) break;
  2914. }
  2915. // nested table drawn below row height fix
  2916. cell->y -= 4; // table y offset
  2917. tempy = cell->y; // table block y
  2918. for (cell = cell; cell <= block; cell ++) // find tr, td, th
  2919. if (cell->tag == CMD('T','R',0,0) ||
  2920. cell->tag == CMD('T','D',0,0) ||
  2921. cell->tag == CMD('T','H',0,0)) break;
  2922. tempy = cell->y - tempy; // get row height
  2923. for (cell = cell; cell <= block; cell ++)
  2924. cell->y -= tempy; // move table up
  2925. block->h -= 2; // /table h offset
  2926. }
  2927. //printf("/table ntables=%d tempx=%d b.x=%d b->x=%d\n",
  2928. // ntables,tempx,b.x,block->x);
  2929. }
  2930. else if (b.tag == CMD('T','D',0,0) ||
  2931. b.tag == CMD('T','H',0,0)) // 'TD' 'TH'
  2932. {
  2933. if (!row) { // no tr
  2934. block->end = tagptr;
  2935. line = do_align(block, line, b.x, newalign, links);
  2936. b.x = block->x;
  2937. block->h += b.h;
  2938. memset(cells, 0, sizeof(cells)); // zero for new row
  2939. b.y = block->y + block->h - 4; // tr gap offset between rows
  2940. block = add_block(b, tagptr, hwidth);
  2941. row = block - blocks_; // next row block number
  2942. column = 0;
  2943. b.h = 0;
  2944. needspace = 0;
  2945. line = 0;
  2946. trpop = 0; // reset tr popped
  2947. }
  2948. if (row) {
  2949. line = do_align(block, line, b.x, newalign, links);
  2950. if (tdline) { block->line = tdline; tdline = 0; } // td popped
  2951. block->end = tagptr;
  2952. block->h += b.h;
  2953. b.y = blocks_[row].y;
  2954. pflag = 1;
  2955. b.x = blocks_[row].x;
  2956. if (liflag) { b.x = margins.pop(); liflag = 0; } // pop li
  2957. b.x += 3 + table_offset; // rem'd + b.fsize
  2958. for (ti = 0; ti < column; ti ++)
  2959. b.x += columns[ti] + 6;
  2960. margins.push(b.x - margins.current());
  2961. //printf("td ntables=%d tempx=%d b.x=%d b->x=%d\n",
  2962. // ntables,tempx,b.x,block->x);
  2963. colspan = 1; // Reset
  2964. if (get_attr(attrptr, "COLSPAN", attr, sizeof(attr)))
  2965. colspan = atoi(attr);
  2966. for (ti = 0, b.w = -6; ti < colspan; ti ++)
  2967. b.w += columns[column + ti] + 6;
  2968. if (block->end == block->start && nblocks_ > 1) {
  2969. nblocks_ --;
  2970. block --;
  2971. }
  2972. if (ntables >= 0)
  2973. d->nfonts = tfonts[ntables]; // pop number of fonts
  2974. b.font = serifont_;
  2975. b.fsize = fontsize_;
  2976. parse_css(b, csstag, tchar);
  2977. if (b.tag == CMD('T','H',0,0)) // th
  2978. b.font = font_style(b.font, FL_BOLD);
  2979. pushfont(b.font, b.fsize);
  2980. block = add_block(b, tagptr, b.x + b.w);
  2981. b.h = 0;
  2982. needspace = 0;
  2983. line = 0;
  2984. newalign = get_align(attrptr, (tag[1] == 'H') ? CENTER : LEFT);
  2985. talign = newalign;
  2986. cells[column] = block - blocks_; // set cell block number
  2987. column += colspan;
  2988. get_attr(attrptr, "BGCOLOR", attr, sizeof(attr));
  2989. block->bgcolor = get_color(attr, rclr);
  2990. }
  2991. }
  2992. else if (b.tag == CMD('/','T','D',0) ||
  2993. b.tag == CMD('/','T','H',0)) // '/TD' '/TH'
  2994. {
  2995. if (row) {
  2996. line = do_align(block, 0, b.x, newalign, links);
  2997. talign = LEFT;
  2998. //popfont(b.font, b.fsize);
  2999. tdline = block->line; // store td line
  3000. b.x = margins.pop();
  3001. pflag = 0; // reset p flag?
  3002. //printf("/td ntables=%d tempx=%d b.x=%d b->x=%d\n",
  3003. // ntables,tempx,b.x,block->x);
  3004. }
  3005. }
  3006. else if (b.tag == CMD('T','I','T',0)) // 'TITLE'
  3007. {
  3008. // Copy the title in the document
  3009. tp = title_ + sizeof(title_) - 1;
  3010. for (sp = title_; *ptr != '<' && *ptr && sp < tp; )
  3011. *(sp ++) = *(ptr ++); // added ()
  3012. *sp = '\0'; // Nul-terminate
  3013. sp = buf;
  3014. }
  3015. else if (b.tag == CMD('T','R',0,0)) // 'TR'
  3016. {
  3017. for (ti = nblocks_ - 1; ti > 0; ti --) { // find last block index
  3018. tempb = blocks_ + ti;
  3019. if (tempb->tag == CMD('T','A','B',0) || tempb->tag == CMD('/','T','A','B') ||
  3020. tempb->tag == CMD('T','D',0,0) || tempb->tag == CMD('T','H',0,0) ||
  3021. tempb->tag == CMD('T','R',0,0) || tempb->tag == CMD('/','T','R',0))
  3022. break; // found table/tr/td tag
  3023. }
  3024. tempx = 0; // no /tr flag
  3025. if (row && tempb->tag != CMD('T','A','B',0)) { // skip first tr after table
  3026. line = do_align(block, line, b.x, newalign, links);
  3027. if (tdline) { // td was popped
  3028. block->line = tdline; tdline = 0; } // last line in td
  3029. block->end = ptr;
  3030. block->h += b.h;
  3031. talign = LEFT;
  3032. if (b.h == 0) b.h = b.fsize + 2; // empty td on end of row
  3033. tempx = b.x;
  3034. b.x = blocks_[row].x;
  3035. b.y = blocks_[row].y + blocks_[row].h;
  3036. for (cell = blocks_ + row + 1; cell <= block; cell ++)
  3037. if (cell->y + cell->h > b.y) b.y = cell->y + cell->h;
  3038. block = blocks_ + row; // current row block ptr
  3039. block->h = b.y - block->y + 2;
  3040. for (ti = 0; ti < column; ti ++)
  3041. if (cells[ti]) { // cell block exists
  3042. cell = blocks_ + cells[ti]; // get cell block ptr
  3043. cell->h = block->h;
  3044. }
  3045. if (tempx) block->x = tempx;
  3046. b.y = block->y + block->h - 4; // tr gap offset between rows
  3047. block = add_block(b, ptr, hwidth);
  3048. needspace = 0;
  3049. row = 0; // reset row block number
  3050. line = 0;
  3051. }
  3052. block->end = tagptr;
  3053. line = do_align(block, line, b.x, newalign, links);
  3054. b.x = block->x;
  3055. block->h += b.h;
  3056. if (row) {
  3057. b.y = blocks_[row].y + blocks_[row].h;
  3058. for (cell = blocks_ + row + 1; cell <= block; cell ++)
  3059. if (cell->y + cell->h > b.y) b.y = cell->y + cell->h;
  3060. block = blocks_ + row; // current row block ptr
  3061. block->h = b.y - block->y + 2;
  3062. for (ti = 0; ti < column; ti ++)
  3063. if (cells[ti]) { // cell block exists
  3064. cell = blocks_ + cells[ti]; // get cell block ptr
  3065. cell->h = block->h;
  3066. }
  3067. }
  3068. memset(cells, 0, sizeof(cells)); // zero for new row
  3069. b.y = block->y + block->h - 4; // tr gap offset between rows
  3070. block = add_block(b, tagptr, hwidth);
  3071. row = block - blocks_; // next row block number
  3072. column = 0;
  3073. b.h = 0;
  3074. needspace = 0;
  3075. line = 0;
  3076. trpop = 0; // reset tr popped
  3077. get_attr(attrptr, "BGCOLOR", attr, sizeof(attr));
  3078. rclr = get_color(attr, tclr);
  3079. }
  3080. else if (b.tag == CMD('/','T','R',0)) // '/TR'
  3081. {
  3082. if (row) { // tr
  3083. line = do_align(block, line, b.x, newalign, links);
  3084. if (tdline) { // td was popped
  3085. block->line = tdline; tdline = 0; } // last line in td
  3086. block->end = ptr;
  3087. block->h += b.h;
  3088. talign = LEFT;
  3089. if (b.h == 0) b.h = b.fsize + 2; // empty td on end of row
  3090. b.x = blocks_[row].x;
  3091. b.y = blocks_[row].y + blocks_[row].h;
  3092. for (cell = blocks_ + row + 1; cell <= block; cell ++)
  3093. if (cell->y + cell->h > b.y) b.y = cell->y + cell->h;
  3094. block = blocks_ + row; // current row block ptr
  3095. block->h = b.y - block->y + 2;
  3096. for (ti = 0; ti < column; ti ++)
  3097. if (cells[ti]) { // cell block exists
  3098. cell = blocks_ + cells[ti]; // get cell block ptr
  3099. cell->h = block->h;
  3100. }
  3101. b.y = block->y + block->h - 4; // tr gap offset between rows
  3102. //printf("/tr row=%d column=%d b.h=%d b->h=%d b->y=%d b.y=%d\n",
  3103. // row,column,b.h,block->h,block->y,b.y);
  3104. block = add_block(b, ptr, hwidth);
  3105. needspace = 0;
  3106. row = 0; // reset row block number
  3107. line = 0;
  3108. }
  3109. else // start margins pop /tr - rem: nested table fix?
  3110. {
  3111. line = do_align(block, line, b.x, newalign, links);
  3112. block->end = ptr;
  3113. b.x = block->x;
  3114. block->h += b.h;
  3115. b.y += b.h;
  3116. trpop = 1; // set tr popped
  3117. b.x = margins.pop(); // pop tr
  3118. while (isspace((*ptr) & 255)) ptr ++;
  3119. block = add_block(b, ptr, hwidth);
  3120. b.h = 0;
  3121. needspace = 0;
  3122. line = 0;
  3123. newalign = talign;
  3124. }
  3125. }
  3126. else if (b.tag == CMD('U',0,0,0)) // 'U'
  3127. {
  3128. }
  3129. else if (b.tag == CMD('V','A','R',0)) // 'VAR'
  3130. {
  3131. b.font = font_style(monofont_, FL_ITALIC);
  3132. pushfont(b.font, b.fsize);
  3133. }
  3134. else if (b.tag == CMD('/','V','A','R')) // '/VAR'
  3135. {
  3136. popfont(b.font, b.fsize);
  3137. }
  3138. else if (b.tag == CMD('A','B','B',0) || // 'ABBR'
  3139. b.tag == CMD('A','C','R',0) || // 'ACRONYM'
  3140. b.tag == CMD('A','D','D',0) || // 'ADDRESS'
  3141. b.tag == CMD('A','P','P',0) || // 'APPLET'
  3142. b.tag == CMD('A','R','E',0) || // 'AREA'
  3143. b.tag == CMD('B','A','S',0) || // 'BASE' 'BASEFONT'
  3144. b.tag == CMD('B','D','O',0) || // 'BDO'
  3145. b.tag == CMD('B','G','S',0) || // 'BGSOUND'
  3146. b.tag == CMD('B','I','G',0) || // 'BIG'
  3147. b.tag == CMD('B','L','I',0) || // 'BLINK'
  3148. b.tag == CMD('B','U','T',0) || // 'BUTTON'
  3149. b.tag == CMD('C','A','P',0) || // 'CAPTION'
  3150. b.tag == CMD('C','I','T',0) || // 'CITE'
  3151. b.tag == CMD('C','O','L',0) || // 'COL' 'COLGROUP'
  3152. b.tag == CMD('D','E','L',0) || // 'DEL'
  3153. b.tag == CMD('D','F','N',0) || // 'DFN'
  3154. b.tag == CMD('D','I','R',0) || // 'DIR'
  3155. b.tag == CMD('E','M','B',0) || // 'EMBED'
  3156. b.tag == CMD('F','I','E',0) || // 'FIELDSET'
  3157. b.tag == CMD('F','O','R',0) || // 'FORM'
  3158. b.tag == CMD('F','R','A',0) || // 'FRAME' 'FRAMESET'
  3159. b.tag == CMD('I','F','R',0) || // 'IFRAME'
  3160. b.tag == CMD('I','N','P',0) || // 'INPUT'
  3161. b.tag == CMD('I','N','S',0) || // 'INS'
  3162. b.tag == CMD('I','S','I',0) || // 'ISINDEX'
  3163. b.tag == CMD('L','A','B',0) || // 'LABEL'
  3164. b.tag == CMD('L','E','G',0) || // 'LEGEND'
  3165. b.tag == CMD('L','I','N',0) || // 'LINK'
  3166. b.tag == CMD('M','A','P',0) || // 'MAP'
  3167. b.tag == CMD('M','A','R',0) || // 'MARQUEE'
  3168. b.tag == CMD('M','E','N',0) || // 'MENU'
  3169. b.tag == CMD('M','E','T',0) || // 'META'
  3170. b.tag == CMD('M','U','L',0) || // 'MULTICOL'
  3171. b.tag == CMD('N','O','B',0) || // 'NOBR'
  3172. b.tag == CMD('N','O','F',0) || // 'NOFRAMES'
  3173. b.tag == CMD('O','B','J',0) || // 'OBJECT'
  3174. b.tag == CMD('O','P','T',0) || // 'OPTGROUP' 'OPTION'
  3175. b.tag == CMD('P','A','R',0) || // 'PARAM'
  3176. b.tag == CMD('Q',0,0,0) || // 'Q'
  3177. b.tag == CMD('S',0,0,0) || // 'S'
  3178. b.tag == CMD('S','A','M',0) || // 'SAMP'
  3179. b.tag == CMD('S','E','L',0) || // 'SELECT'
  3180. b.tag == CMD('S','M','A',0) || // 'SMALL'
  3181. b.tag == CMD('S','P','A',0) || // 'SPACER' 'SPAN'
  3182. b.tag == CMD('S','T','R',0) || // 'STRIKE'
  3183. b.tag == CMD('S','T','Y',0) || // 'STYLE'
  3184. b.tag == CMD('S','U','B',0) || // 'SUB'
  3185. b.tag == CMD('S','U','P',0) || // 'SUP'
  3186. b.tag == CMD('T','B','O',0) || // 'TBODY'
  3187. b.tag == CMD('T','E','X',0) || // 'TEXTAREA'
  3188. b.tag == CMD('T','F','O',0) || // 'TFOOT'
  3189. b.tag == CMD('T','H','E',0) || // 'THEAD'
  3190. b.tag == CMD('W','B','R',0) || // 'WBR'
  3191. b.tag == CMD('X','M','P',0)) // 'XMP'
  3192. ; // unsupported tags
  3193. else if (tag[0] == '!' && isalpha(tag[1])) // '!DOCTYPE' etc
  3194. ;
  3195. else if (tag[0] == '?' && isalpha(tag[1])) // '?XMP' etc
  3196. ;
  3197. else if (tag[0] == '/' && isalpha(tag[1])) // unrecognized end tag
  3198. ;
  3199. else if (!head) // unrecognized tag so draw it
  3200. {
  3201. b.x += (int)fl_width("<"); // add width of '<' char
  3202. linew += (int)fl_width("<");
  3203. ptr = tagptr + 1; // start of tag + 1
  3204. }
  3205. } // if (*ptr == '<')
  3206. else if (*ptr == '\n' && b.pre) // '\n' in pre
  3207. {
  3208. if (linkdest[0])
  3209. add_link(linkdest, b.x, b.y - b.h, b.w, b.h);
  3210. if (b.x > hsize_) { // Reformat
  3211. hsize_ = b.x + 4;
  3212. done = 0;
  3213. }
  3214. block->end = ptr;
  3215. line = do_align(block, 0, b.x, newalign, links);
  3216. b.x = block->x;
  3217. block->h += b.h;
  3218. b.y += b.h; //b.y = block->y + block->h;
  3219. line = 0;
  3220. linew = 0;
  3221. block = add_block(b, ptr, (row) ? block->w : hwidth);
  3222. b.h = 0;
  3223. needspace = 0;
  3224. ptr ++;
  3225. }
  3226. else if (isspace((*ptr) & 255)) // ' ' '\t'\n'\v'\f'\r' chars
  3227. {
  3228. needspace = 1;
  3229. ptr ++;
  3230. }
  3231. else if (*ptr == '&' && sp < (buf + sizeof(buf) - 1)) // '&' char ref
  3232. {
  3233. ptr ++;
  3234. qch = quote_char(ptr);
  3235. if (qch < 0)
  3236. *(sp ++) = '&'; // added ()
  3237. else {
  3238. *(sp ++) = qch; // added ()
  3239. ptr = strchr(ptr, ';') + 1;
  3240. }
  3241. if (b.fsize + 2 > b.h) b.h = b.fsize + 2; // Set b.h
  3242. }
  3243. else // Other char
  3244. {
  3245. if (sp < (buf + sizeof(buf) - 1))
  3246. *(sp ++) = *(ptr ++); // added ()
  3247. else
  3248. ptr ++;
  3249. if (b.fsize + 2 > b.h) b.h = b.fsize + 2; // Set b.h
  3250. }
  3251. //if (d->resized && block->y + block->h > topline_ + h())
  3252. //break; // if resizing big page skip non-visible region
  3253. } // for (ptr = value_ ...)
  3254. if (sp > buf) // Still something left to parse
  3255. {
  3256. if (!head) // Normal text... b.pre fixme?
  3257. {
  3258. *sp = '\0'; // Nul-terminate
  3259. b.w = (int)fl_width(buf);
  3260. //printf("line = %d, b.x = %d, b.w = %d, block->x = %d, block->w = %d\n",
  3261. // line, b.x, b.w, block->x, block->w);
  3262. if (b.w > hsize_) { // Reformat
  3263. hsize_ = b.w;
  3264. done = 0;
  3265. }
  3266. if (needspace && b.x > block->x)
  3267. b.w += (int)fl_width(" ");
  3268. // no new line if word too long and no word before it
  3269. if (!(b.x < 7 && b.w > block->w) && (b.x + b.w) > block->w) {
  3270. block->end = ptr - strlen(buf);
  3271. line = do_align(block, 0, b.x, newalign, links);
  3272. b.x = block->x;
  3273. block->h += b.h;
  3274. b.y += b.h; //b.y = block->y + block->h;
  3275. b.h = 0;
  3276. line = 0;
  3277. block = add_block(b, ptr - strlen(buf), (row) ? block->w : hwidth);
  3278. }
  3279. if (linkdest[0])
  3280. add_link(linkdest, b.x, b.y - b.fsize, b.w, b.fsize);
  3281. b.x += b.w;
  3282. }
  3283. }
  3284. do_align(block, line, b.x, newalign, links);
  3285. block->end = ptr;
  3286. size_ = b.y + b.h;
  3287. //if (d->resized && block->y + block->h > topline_ + h())
  3288. //break; // if resizing big page skip non-visible region
  3289. } // while (!done)
  3290. d->isnew = 0; // reset - so we know a repeat call to format per page, to stabilize malloc
  3291. //printf("margins.depth_=%d\n", margins.depth_);
  3292. if (ntargets_ > 1)
  3293. qsort(d->targets, ntargets_, sizeof(Fl_Help_Link),
  3294. (compare_func_t)cmp_targets);
  3295. dx = Fl::box_dw(bt) - Fl::box_dx(bt);
  3296. dy = Fl::box_dh(bt) - Fl::box_dy(bt);
  3297. ss = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size();
  3298. dw = Fl::box_dw(bt) + ss;
  3299. dh = Fl::box_dh(bt);
  3300. //if (d->resized && block->y + block->h > topline_ + h())
  3301. //return; // if resizing big page skip resizing scrollbars
  3302. if (hsize_ > (w() - dw))
  3303. {
  3304. hscrollbar_.show();
  3305. dh += ss;
  3306. if (size_ < (h() - dh)) {
  3307. scrollbar_.hide();
  3308. hscrollbar_.resize(x() + Fl::box_dx(bt), y() + h() - ss - dy,
  3309. w() - Fl::box_dw(bt), ss);
  3310. }
  3311. else {
  3312. scrollbar_.show();
  3313. scrollbar_.resize(x() + w() - ss - dx, y() + Fl::box_dy(bt),
  3314. ss, h() - ss - Fl::box_dh(bt));
  3315. hscrollbar_.resize(x() + Fl::box_dx(bt), y() + h() - ss - dy,
  3316. w() - ss - Fl::box_dw(bt), ss);
  3317. }
  3318. }
  3319. else // If hsize_ <= (w() - dw)
  3320. {
  3321. hscrollbar_.hide();
  3322. if (size_ < (h() - dh))
  3323. scrollbar_.hide();
  3324. else {
  3325. scrollbar_.resize(x() + w() - ss - dx, y() + Fl::box_dy(bt),
  3326. ss, h() - Fl::box_dh(bt));
  3327. scrollbar_.show();
  3328. }
  3329. }
  3330. // Reset scrolling if it needs to be
  3331. if (scrollbar_.visible()) {
  3332. temph = h() - Fl::box_dh(bt);
  3333. if (hscrollbar_.visible()) temph -= ss;
  3334. if ((topline_ + temph) > size_) topline(size_ - temph);
  3335. else topline(topline_);
  3336. }
  3337. else
  3338. topline(0);
  3339. if (hscrollbar_.visible()) {
  3340. tempw = w() - ss - Fl::box_dw(bt);
  3341. if (leftline_ + tempw > hsize_)
  3342. leftline(hsize_ - tempw);
  3343. else
  3344. leftline(leftline_);
  3345. }
  3346. else
  3347. leftline(0);
  3348. } // Fl_Help_View::format()
  3349. //
  3350. // Fl_Help_View::format_table() - replaced, code moved
  3351. //
  3352. void Fl_Help_View::format_table(int *tw, // O - Total table width
  3353. int *maxcols, // O - Column widths
  3354. const char *tp) // I - Table start pointer
  3355. {
  3356. return;
  3357. } // Fl_Help_View::format_table()
  3358. //
  3359. // Fl_Help_View::format_table() - Format a table.
  3360. //
  3361. const char * // O - table end pointer
  3362. Fl_Help_View::format_table(int &tw, // O - Total table width
  3363. int *maxcols, // O - Column widths
  3364. const char *tp, // I - Table start pointer
  3365. int xx, // I - x position of table
  3366. int rc) // I - recursive counter
  3367. {
  3368. char *sp, // Pointer into buffer
  3369. buf[1024], // Text buffer
  3370. attr[1024], // Other attribute
  3371. wattr[1024], // WIDTH attribute
  3372. hattr[1024], // HEIGHT attribute
  3373. tag[4]; // tag/element 4-char buf
  3374. const char *ptr, // Pointer into table
  3375. *attrptr, // Start of attributes ptr
  3376. *tagptr, // Start of tag/element ptr
  3377. *endp; // table end pointer
  3378. int col = 0, // Current column
  3379. numcells = 0, // Number of cells
  3380. colspan = 0, // COLSPAN attribute
  3381. linew = 0, // Current line width
  3382. tempw = 0, // Temporary width
  3383. maxlinew = 0, // Maximum width
  3384. mincellw = 0, // minimum table width
  3385. maxcellw = 0, // total width of cells
  3386. colspanw = 0, // colspan width
  3387. scalew = 0, // Table scaled width
  3388. hwidth = 0, // horizontal window width
  3389. tsize = 0, // table size
  3390. incell = 0, // In a table cell?
  3391. head = 0, // head/body section flag
  3392. pre = 0, // Pre text flag
  3393. btag = 0, // tag/element fourcc int
  3394. needspace = 0, // Do we need whitespace?
  3395. ti = 0, // temp loop var
  3396. imgw = 0, // Image width
  3397. imgh = 0, // Image height
  3398. qch = 0, // Quote char
  3399. nfonts = 0, // local font stack index
  3400. font = 0; // Current font
  3401. unsigned char fsize; // Current font size
  3402. int mincols[HV_64], // Minimum widths for each column
  3403. widths[HV_64], // td width attributes
  3404. colspans[HV_64], // min width in colspan cells
  3405. columns[HV_64], // nested table column widths
  3406. fonts[HV_64][2]; // local font stack
  3407. Fl_Shared_Image *img = 0; // Shared image - rem'd NULL
  3408. Fl_Boxtype bt = (box()) ? box() : FL_DOWN_BOX; // Box size
  3409. tw = 0; // Clear widths
  3410. endp = 0; // rem'd NULL
  3411. // zero arrays
  3412. memset(mincols, 0, sizeof(mincols));
  3413. memset(widths, 0, sizeof(widths));
  3414. memset(colspans, 0, sizeof(colspans));
  3415. memset(columns, 0, sizeof(columns));
  3416. hwidth = w() - (scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size()) - Fl::box_dw(bt);
  3417. font = fonts[nfonts][0] = serifont_; // initfont
  3418. fsize = fonts[nfonts][1] = fontsize_;
  3419. fl_font(font, fsize);
  3420. //printf("\nFORMAT_TABLE %d\n",tp - value_);
  3421. col = -1;
  3422. linew = 0;
  3423. incell = 0;
  3424. // Scan the table
  3425. for (ptr = tp, sp = buf; *ptr; )
  3426. {
  3427. if ((*ptr == '<' || isspace((*ptr) & 255)) && sp > buf)
  3428. {
  3429. if (needspace) { // Check width
  3430. *(sp ++) = ' '; // added ()
  3431. needspace = 0;
  3432. }
  3433. *sp = '\0'; // Nul-terminate
  3434. sp = buf;
  3435. if (incell && !head && !pre) // Normal text
  3436. {
  3437. tempw = (int)fl_width(buf); // Width of current word
  3438. if (tempw > mincols[col] && colspan <= 1)
  3439. mincols[col] = tempw; // ignore if colspan > 1
  3440. if (tempw > colspans[col] && colspan > 1) {
  3441. colspans[col] = tempw; // colspans
  3442. colspans[col] -= 6 * (colspan - 1); // sub internal borders
  3443. if (colspans[col] < 6 * (colspan - 1))
  3444. colspans[col] = tempw; // reset thin cell widths
  3445. colspans[col + 1] = colspan;
  3446. }
  3447. linew += tempw;
  3448. if (linew > maxlinew) maxlinew = linew;
  3449. }
  3450. else if (incell && !head && pre) // pre text
  3451. {
  3452. tempw = (int)fl_width(buf); // Width of current word
  3453. linew += tempw; // pre text in tables not increasing cell width fix
  3454. if (linew > maxlinew) maxlinew = linew;
  3455. //printf("ptr=%c head=%d pre=%d incell=%d tw=%d lw=%d %s\n",
  3456. // *ptr,head,pre,incell,tempw,linew,buf);
  3457. if (*ptr == '\n') { // newline char
  3458. if (linew > mincols[col] && colspan <= 1)
  3459. mincols[col] = linew; // ignore if colspan > 1
  3460. if (linew > colspans[col] && colspan > 1) {
  3461. colspans[col] = linew; // colspans
  3462. colspans[col] -= 5 * (colspan - 1); // sub internal borders
  3463. if (colspans[col] < 5 * (colspan - 1))
  3464. colspans[col] = linew; // reset thin cell widths
  3465. colspans[col + 1] = colspan;
  3466. }
  3467. }
  3468. else if (*ptr == '\t') { // tab char
  3469. ti = linew / (int)fl_width(" "); // number of chars, monospace
  3470. tempw = 7 - (ti & 7); // number of tabs 0..7
  3471. if (tempw) // pre tabs width fix
  3472. linew += tempw * (int)fl_width(" ");
  3473. }
  3474. }
  3475. }
  3476. if (*ptr == '<')
  3477. {
  3478. tagptr = ptr; // Start of tag
  3479. ptr ++; // inc ptr
  3480. sp = buf; // reset sp
  3481. if (!strncmp(ptr, "!--", 3)) { // Found "!--"
  3482. ptr += 3;
  3483. if ((ptr = strstr(ptr, "-->"))) { // Skip comment - rem'd != 0
  3484. ptr += 3;
  3485. continue;
  3486. }
  3487. else
  3488. break;
  3489. }
  3490. while (*ptr && *ptr != '>' && !isspace((*ptr) & 255)) // was for loop
  3491. if (sp < (buf + sizeof(buf) - 1))
  3492. *(sp ++) = *(ptr ++); // added ()
  3493. else
  3494. ptr ++;
  3495. *sp = '\0'; // Nul-terminate
  3496. sp = buf;
  3497. attrptr = ptr; // Start of attributes
  3498. while (*ptr && *ptr != '>') ptr ++;
  3499. if (*ptr == '>') ptr ++;
  3500. btag = strlen(buf); // store strlen
  3501. if (btag > 4) btag = 4; // limit
  3502. for (ti = 0; ti < btag; ti ++) // abbreviate tag, to uppercase
  3503. tag[ti] = toupper(buf[ti]);
  3504. for (ti = btag; ti < 4; ti ++) // set chars after to nul
  3505. tag[ti] = 0;
  3506. if (buf[0] != '/' && btag > 3) tag[3] = 0; // eg. HTML=HTM
  3507. btag = CMD(tag[0],tag[1],tag[2],tag[3]); // tag as int
  3508. // End of command reached
  3509. if (btag == CMD('A',0,0,0)) // 'A'
  3510. {
  3511. }
  3512. else if (btag == CMD('B',0,0,0) ||
  3513. btag == CMD('S','T','R',0)) // 'B' 'STRONG'
  3514. {
  3515. font = font_style(font, FL_BOLD);
  3516. if (nfonts < HV_64 - 1) nfonts ++; // pushfont
  3517. fl_font(fonts[nfonts][0] = font, fonts[nfonts][1] = fsize);
  3518. }
  3519. else if (btag == CMD('/','B',0,0) ||
  3520. btag == CMD('/','S','T','R')) // '/B' '/STRONG'
  3521. {
  3522. if (nfonts > 0) nfonts --; // popfont
  3523. fl_font(font = fonts[nfonts][0], fsize = fonts[nfonts][1]);
  3524. }
  3525. else if (btag == CMD('B','L','O',0) ||
  3526. btag == CMD('D','L',0,0) ||
  3527. btag == CMD('U','L',0,0) ||
  3528. btag == CMD('O','L',0,0) ||
  3529. btag == CMD('D','D',0,0) ||
  3530. btag == CMD('D','T',0,0)) // 'BLOCKQUOTE' 'DL'OL'UL'
  3531. {
  3532. linew = 0;
  3533. needspace = 0;
  3534. }
  3535. else if (btag == CMD('/','B','L','O') ||
  3536. btag == CMD('/','D','L',0) ||
  3537. btag == CMD('/','O','L',0) ||
  3538. btag == CMD('/','U','L',0)) // '/BLOCKQUOTE' '/DL'/OL'/UL'
  3539. {
  3540. linew = 0;
  3541. needspace = 0;
  3542. }
  3543. else if (btag == CMD('B','O','D',0)) // 'BODY'
  3544. {
  3545. }
  3546. else if (btag == CMD('B','R',0,0)) // 'BR'
  3547. {
  3548. linew = 0;
  3549. needspace = 0;
  3550. }
  3551. else if (btag == CMD('C','E','N',0)) // 'CENTER'
  3552. {
  3553. linew = 0;
  3554. needspace = 0;
  3555. }
  3556. else if (btag == CMD('/','C','E','N')) // '/CENTER'
  3557. {
  3558. linew = 0;
  3559. needspace = 0;
  3560. }
  3561. else if (btag == CMD('C','O','D',0) ||
  3562. btag == CMD('T','T',0,0)) // 'CODE' 'TT'
  3563. {
  3564. font = monofont_;
  3565. if (nfonts < HV_64 - 1) nfonts ++; // pushfont
  3566. fl_font(fonts[nfonts][0] = font, fonts[nfonts][1] = fsize);
  3567. }
  3568. else if (btag == CMD('/','C','O','D') ||
  3569. btag == CMD('/','T','T',0)) // '/CODE' '/TT'
  3570. {
  3571. if (nfonts > 0) nfonts --; // popfont
  3572. fl_font(font = fonts[nfonts][0], fsize = fonts[nfonts][1]);
  3573. }
  3574. else if (btag == CMD('D','I','V',0)) // 'DIV'
  3575. {
  3576. linew = 0;
  3577. needspace = 0;
  3578. }
  3579. else if (btag == CMD('/','D','I','V')) // '/DIV'
  3580. {
  3581. linew = 0;
  3582. needspace = 0;
  3583. }
  3584. else if (btag == CMD('F','O','N',0)) // 'FONT'
  3585. {
  3586. if (get_attr(attrptr, "FACE", attr, sizeof(attr)))
  3587. font = font_face(attr);
  3588. if (get_attr(attrptr, "SIZE", attr, sizeof(attr))) {
  3589. if (isdigit(attr[0])) // Absolute size
  3590. fsize = (int)(fontsize_ * pow(1.2, atoi(attr) - 3.0));
  3591. else // Relative size
  3592. fsize = (int)(fsize * pow(1.2, atoi(attr)));
  3593. }
  3594. if (nfonts < HV_64 - 1) nfonts ++; // pushfont
  3595. fl_font(fonts[nfonts][0] = font, fonts[nfonts][1] = fsize);
  3596. }
  3597. else if (btag == CMD('/','F','O','N')) // '/FONT'
  3598. {
  3599. if (nfonts > 0) nfonts --; // popfont
  3600. fl_font(font = fonts[nfonts][0], fsize = fonts[nfonts][1]);
  3601. }
  3602. else if (tag[0] == 'H' && isdigit(tag[1])) // 'H1'
  3603. {
  3604. linew = 0;
  3605. needspace = 0;
  3606. font = font_style(font, FL_BOLD);
  3607. switch (tag[1]) { // header sizes
  3608. case '1' : fsize = 24; break;
  3609. case '2' : fsize = 18; break;
  3610. case '3' : fsize = 16; break;
  3611. case '4' : fsize = 14; break;
  3612. case '5' : fsize = 12; break;
  3613. case '6' : fsize = 10; break;
  3614. default : fsize = fontsize_; font = serifont_; break;
  3615. }
  3616. if (nfonts < HV_64 - 1) nfonts ++; // pushfont
  3617. fl_font(fonts[nfonts][0] = font, fonts[nfonts][1] = fsize);
  3618. }
  3619. else if (btag == CMD('/','H',tag[2],0) && isdigit(tag[2])) // '/H1'
  3620. {
  3621. linew = 0;
  3622. needspace = 0;
  3623. if (nfonts > 0) nfonts --; // popfont
  3624. fl_font(font = fonts[nfonts][0], fsize = fonts[nfonts][1]);
  3625. }
  3626. else if (btag == CMD('H','E','A',0)) // 'HEAD'
  3627. {
  3628. head = 1;
  3629. }
  3630. else if (btag == CMD('/','H','E','A')) // '/HEAD'
  3631. {
  3632. head = 0;
  3633. }
  3634. else if (btag == CMD('H','R',0,0)) // 'HR'
  3635. {
  3636. linew = 0;
  3637. needspace = 0;
  3638. }
  3639. else if (btag == CMD('H','T','M',0)) // 'HTML'
  3640. {
  3641. }
  3642. else if (btag == CMD('I',0,0,0) ||
  3643. btag == CMD('E','M',0,0)) // 'I' 'EM'
  3644. {
  3645. font = font_style(font, FL_ITALIC);
  3646. if (nfonts < HV_64 - 1) nfonts ++; // pushfont
  3647. fl_font(fonts[nfonts][0] = font, fonts[nfonts][1] = fsize);
  3648. }
  3649. else if (btag == CMD('/','I',0,0) ||
  3650. btag == CMD('/','E','M',0)) // '/I' '/EM'
  3651. {
  3652. if (nfonts > 0) nfonts --; // popfont
  3653. fl_font(font = fonts[nfonts][0], fsize = fonts[nfonts][1]);
  3654. }
  3655. else if (btag == CMD('I','M','G',0)) // 'IMG'
  3656. {
  3657. if (incell) {
  3658. imgw = imgh = 0; // reset
  3659. if (get_attr(attrptr, "WIDTH", wattr, sizeof(wattr)))
  3660. imgw = get_length(wattr);
  3661. if (get_attr(attrptr, "HEIGHT", hattr, sizeof(hattr)))
  3662. imgh = get_length(hattr);
  3663. img = 0; // rem'd NULL
  3664. if (get_attr(attrptr, "SRC", attr, sizeof(attr))) {
  3665. img = get_image(attr, imgw, imgh); // Use src values
  3666. imgw = img->w();
  3667. imgh = img->h();
  3668. }
  3669. if (imgw > mincols[col]) mincols[col] = imgw;
  3670. linew += imgw;
  3671. if (needspace) {
  3672. linew += (int)fl_width(" ");
  3673. needspace = 0;
  3674. }
  3675. if (linew > maxlinew) maxlinew = linew;
  3676. }
  3677. }
  3678. else if (btag == CMD('K','B','D',0)) // 'KBD'
  3679. {
  3680. font = font_style(monofont_, FL_BOLD);
  3681. if (nfonts < HV_64 - 1) nfonts ++; // pushfont
  3682. fl_font(fonts[nfonts][0] = font, fonts[nfonts][1] = fsize);
  3683. }
  3684. else if (btag == CMD('/','K','B','D')) // '/KBD'
  3685. {
  3686. if (nfonts > 0) nfonts --; // popfont
  3687. fl_font(font = fonts[nfonts][0], fsize = fonts[nfonts][1]);
  3688. }
  3689. else if (btag == CMD('L','I',0,0)) // 'LI'
  3690. {
  3691. linew = 0;
  3692. needspace = 0;
  3693. linew += fsize; // changed 4 * fsize
  3694. }
  3695. else if (btag == CMD('/','L','I',0)) // '/LI'
  3696. {
  3697. linew = 0;
  3698. needspace = 0;
  3699. }
  3700. else if (btag == CMD('N','O','S',0)) // 'NOSCRIPT'
  3701. { // we don't support scripting so we won't skip this
  3702. }
  3703. else if (btag == CMD('P',0,0,0)) // 'P'
  3704. {
  3705. linew = 0;
  3706. needspace = 0;
  3707. }
  3708. else if (btag == CMD('/','P',0,0)) // '/P'
  3709. {
  3710. linew = 0;
  3711. needspace = 0;
  3712. }
  3713. else if (btag == CMD('P','R','E',0)) // 'PRE'
  3714. {
  3715. linew = 0;
  3716. needspace = 0;
  3717. pre = 1;
  3718. font = monofont_;
  3719. fsize = fontsize_;
  3720. if (nfonts < HV_64 - 1) nfonts ++; // pushfont
  3721. fl_font(fonts[nfonts][0] = font, fonts[nfonts][1] = fsize);
  3722. }
  3723. else if (btag == CMD('/','P','R','E')) // '/PRE'
  3724. {
  3725. linew = 0;
  3726. needspace = 0;
  3727. pre = 0;
  3728. if (nfonts > 0) nfonts --; // popfont
  3729. fl_font(font = fonts[nfonts][0], fsize = fonts[nfonts][1]);
  3730. }
  3731. else if (btag == CMD('S','C','R',0)) // 'SCRIPT'
  3732. {
  3733. while (ptr) { // skip scripting
  3734. ptr = strstr(ptr, "</");
  3735. if (!strncasecmp(ptr, "</SCRIPT>", 9)) break;
  3736. }
  3737. if (ptr) { // found </script>
  3738. ptr += 9;
  3739. continue;
  3740. }
  3741. else // not found
  3742. break;
  3743. }
  3744. else if (btag == CMD('T','A','B',0)) // 'TABLE'
  3745. {
  3746. linew = 0; // cell width not reset before nested table fix
  3747. needspace = 0;
  3748. if (tagptr > tp) { // nested table
  3749. if (rc < HV_16) // limit recursive function
  3750. endp = format_table(scalew, columns, tagptr, xx, rc + 1);
  3751. if (endp) ptr = endp; // to skip nested table
  3752. for (ti = 0; ti < HV_64; ti ++)
  3753. if (columns[ti] == 0) break; // num columns
  3754. scalew += ti * 6; // add internal borders
  3755. if (scalew > mincols[col]) // set nested width
  3756. mincols[col] = scalew;
  3757. linew += scalew;
  3758. if (linew > maxlinew) maxlinew = linew;
  3759. linew = 0; // cell width not reset after nested table fix
  3760. needspace = 0;
  3761. }
  3762. }
  3763. else if (btag == CMD('/','T','A','B')) // '/TABLE'
  3764. {
  3765. //printf("%s col = %d, colspan = %d, numcells = %d\n",
  3766. // buf, col, colspan, numcells);
  3767. if (col >= 0) { // This is a hack to support COLSPAN
  3768. ti = colspan; // ignore if colspan > 1
  3769. maxlinew /= colspan;
  3770. while (colspan > 0) {
  3771. if (maxlinew > maxcols[col] && ti <= 1)
  3772. maxcols[col] = maxlinew;
  3773. col ++;
  3774. colspan --;
  3775. }
  3776. }
  3777. endp = ptr; // store nested table end ptr
  3778. break; // exit for (ptr = tp ...) loop
  3779. }
  3780. else if (btag == CMD('T','D',0,0) ||
  3781. btag == CMD('T','H',0,0)) // 'TD' 'TH'
  3782. {
  3783. //printf("BEFORE col = %d, colspan = %d, numcells = %d\n",
  3784. // col, colspan, numcells);
  3785. if (col >= 0) { // This is a hack to support COLSPAN
  3786. ti = colspan; // ignore if colspan > 1
  3787. maxlinew /= colspan;
  3788. while (colspan > 0) {
  3789. if (maxlinew > maxcols[col] && ti <= 1)
  3790. maxcols[col] = maxlinew;
  3791. col ++;
  3792. colspan --;
  3793. }
  3794. }
  3795. else
  3796. col ++;
  3797. colspan = 1; // Reset
  3798. if (get_attr(attrptr, "COLSPAN", attr, sizeof(attr)))
  3799. colspan = atoi(attr);
  3800. //printf("AFTER col = %d, colspan = %d, numcells = %d\n",
  3801. // col, colspan, numcells);
  3802. if (col + colspan >= numcells)
  3803. numcells = col + colspan;
  3804. linew = 0;
  3805. needspace = 0;
  3806. incell = 1;
  3807. if (btag == CMD('T','H',0,0)) // th
  3808. font = font_style(serifont_, FL_BOLD);
  3809. else
  3810. font = serifont_;
  3811. fsize = fontsize_;
  3812. nfonts = 0; // pop all fonts off stack, no need for anything more
  3813. if (nfonts < HV_64 - 1) nfonts ++; // pushfont
  3814. fl_font(fonts[nfonts][0] = font, fonts[nfonts][1] = fsize);
  3815. maxlinew = 0; // Reset
  3816. if (get_attr(attrptr, "WIDTH", attr, sizeof(attr))) {
  3817. maxlinew = get_length(attr, hsize_ - xx);
  3818. if (maxlinew > widths[col])
  3819. widths[col] = maxlinew; // store widths
  3820. }
  3821. //printf("maxlinew = %d\n", maxlinew);
  3822. }
  3823. else if (btag == CMD('/','T','D',0) ||
  3824. btag == CMD('/','T','H',0)) // '/TD' '/TH'
  3825. {
  3826. incell = 0;
  3827. }
  3828. else if (btag == CMD('T','I','T',0)) // 'TITLE'
  3829. {
  3830. }
  3831. else if (btag == CMD('T','R',0,0)) // 'TR'
  3832. {
  3833. //printf("%s col = %d, colspan = %d, numcells = %d\n",
  3834. // buf, col, colspan, numcells);
  3835. if (col >= 0) { // This is a hack to support COLSPAN
  3836. ti = colspan; // ignore if colspan > 1
  3837. maxlinew /= colspan;
  3838. while (colspan > 0) {
  3839. if (maxlinew > maxcols[col] && ti <= 1)
  3840. maxcols[col] = maxlinew;
  3841. col ++;
  3842. colspan --;
  3843. }
  3844. }
  3845. linew = 0;
  3846. needspace = 0;
  3847. incell = 0;
  3848. col = -1;
  3849. maxlinew = 0;
  3850. }
  3851. else if (btag == CMD('/','T','R',0)) // '/TR'
  3852. {
  3853. //printf("%s col = %d, colspan = %d, numcells = %d\n",
  3854. // buf, col, colspan, numcells);
  3855. if (col >= 0) { // This is a hack to support COLSPAN
  3856. ti = colspan; // ignore if colspan > 1
  3857. maxlinew /= colspan;
  3858. while (colspan > 0) {
  3859. if (maxlinew > maxcols[col] && ti <= 1)
  3860. maxcols[col] = maxlinew;
  3861. col ++;
  3862. colspan --;
  3863. }
  3864. }
  3865. linew = 0;
  3866. needspace = 0;
  3867. incell = 0;
  3868. col = -1;
  3869. maxlinew = 0;
  3870. }
  3871. else if (btag == CMD('U',0,0,0)) // 'U'
  3872. {
  3873. }
  3874. else if (btag == CMD('V','A','R',0)) // 'VAR'
  3875. {
  3876. font = font_style(monofont_, FL_ITALIC);
  3877. if (nfonts < HV_64 - 1) nfonts ++; // pushfont
  3878. fl_font(fonts[nfonts][0] = font, fonts[nfonts][1] = fsize);
  3879. }
  3880. else if (btag == CMD('/','V','A','R')) // '/VAR'
  3881. {
  3882. if (nfonts > 0) nfonts --; // popfont
  3883. fl_font(font = fonts[nfonts][0], fsize = fonts[nfonts][1]);
  3884. }
  3885. else if (btag == CMD('A','B','B',0) || // 'ABBR'
  3886. btag == CMD('A','C','R',0) || // 'ACRONYM'
  3887. btag == CMD('A','D','D',0) || // 'ADDRESS'
  3888. btag == CMD('A','P','P',0) || // 'APPLET'
  3889. btag == CMD('A','R','E',0) || // 'AREA'
  3890. btag == CMD('B','A','S',0) || // 'BASE' 'BASEFONT'
  3891. btag == CMD('B','D','O',0) || // 'BDO'
  3892. btag == CMD('B','G','S',0) || // 'BGSOUND'
  3893. btag == CMD('B','I','G',0) || // 'BIG'
  3894. btag == CMD('B','L','I',0) || // 'BLINK'
  3895. btag == CMD('B','U','T',0) || // 'BUTTON'
  3896. btag == CMD('C','A','P',0) || // 'CAPTION'
  3897. btag == CMD('C','I','T',0) || // 'CITE'
  3898. btag == CMD('C','O','L',0) || // 'COL' 'COLGROUP'
  3899. btag == CMD('D','E','L',0) || // 'DEL'
  3900. btag == CMD('D','F','N',0) || // 'DFN'
  3901. btag == CMD('D','I','R',0) || // 'DIR'
  3902. btag == CMD('E','M','B',0) || // 'EMBED'
  3903. btag == CMD('F','I','E',0) || // 'FIELDSET'
  3904. btag == CMD('F','O','R',0) || // 'FORM'
  3905. btag == CMD('F','R','A',0) || // 'FRAME' 'FRAMESET'
  3906. btag == CMD('I','F','R',0) || // 'IFRAME'
  3907. btag == CMD('I','N','P',0) || // 'INPUT'
  3908. btag == CMD('I','N','S',0) || // 'INS'
  3909. btag == CMD('I','S','I',0) || // 'ISINDEX'
  3910. btag == CMD('L','A','B',0) || // 'LABEL'
  3911. btag == CMD('L','E','G',0) || // 'LEGEND'
  3912. btag == CMD('L','I','N',0) || // 'LINK'
  3913. btag == CMD('M','A','P',0) || // 'MAP'
  3914. btag == CMD('M','A','R',0) || // 'MARQUEE'
  3915. btag == CMD('M','E','N',0) || // 'MENU'
  3916. btag == CMD('M','E','T',0) || // 'META'
  3917. btag == CMD('M','U','L',0) || // 'MULTICOL'
  3918. btag == CMD('N','O','B',0) || // 'NOBR'
  3919. btag == CMD('N','O','F',0) || // 'NOFRAMES'
  3920. btag == CMD('O','B','J',0) || // 'OBJECT'
  3921. btag == CMD('O','P','T',0) || // 'OPTGROUP' 'OPTION'
  3922. btag == CMD('P','A','R',0) || // 'PARAM'
  3923. btag == CMD('Q',0,0,0) || // 'Q'
  3924. btag == CMD('S',0,0,0) || // 'S'
  3925. btag == CMD('S','A','M',0) || // 'SAMP'
  3926. btag == CMD('S','E','L',0) || // 'SELECT'
  3927. btag == CMD('S','M','A',0) || // 'SMALL'
  3928. btag == CMD('S','P','A',0) || // 'SPACER' 'SPAN'
  3929. btag == CMD('S','T','R',0) || // 'STRIKE'
  3930. btag == CMD('S','T','Y',0) || // 'STYLE'
  3931. btag == CMD('S','U','B',0) || // 'SUB'
  3932. btag == CMD('S','U','P',0) || // 'SUP'
  3933. btag == CMD('T','B','O',0) || // 'TBODY'
  3934. btag == CMD('T','E','X',0) || // 'TEXTAREA'
  3935. btag == CMD('T','F','O',0) || // 'TFOOT'
  3936. btag == CMD('T','H','E',0) || // 'THEAD'
  3937. btag == CMD('W','B','R',0) || // 'WBR'
  3938. btag == CMD('X','M','P',0)) // 'XMP'
  3939. ; // unsupported tags
  3940. else if (tag[0] == '!' && isalpha(tag[1])) // '!DOCTYPE' etc
  3941. ;
  3942. else if (tag[0] == '?' && isalpha(tag[1])) // '?XMP' etc
  3943. ;
  3944. else if (tag[0] == '/' && isalpha(tag[1])) // unrecognized end tag
  3945. ;
  3946. else if (!head) // unrecognized tag so draw it
  3947. {
  3948. linew += (int)fl_width("<"); // add width of '<' char
  3949. ptr = tagptr + 1; // start of tag + 1
  3950. }
  3951. } // if (*ptr == '<')
  3952. else if (*ptr == '\n' && pre) // '\n' in pre
  3953. {
  3954. linew = 0;
  3955. needspace = 0;
  3956. ptr ++;
  3957. }
  3958. else if (isspace((*ptr) & 255)) // ' ' '\t'\n'\v'\f'\r' chars
  3959. {
  3960. needspace = 1;
  3961. ptr ++;
  3962. }
  3963. else if (*ptr == '&' && sp < (buf + sizeof(buf) - 1)) // '&' char ref
  3964. {
  3965. ptr ++;
  3966. qch = quote_char(ptr);
  3967. if (qch < 0) // Not char ref
  3968. *(sp ++) = '&'; // added ()
  3969. else {
  3970. *(sp ++) = qch; // added ()
  3971. ptr = strchr(ptr, ';') + 1;
  3972. }
  3973. }
  3974. else // Other char
  3975. {
  3976. if (sp < (buf + sizeof(buf) - 1))
  3977. *(sp ++) = *(ptr ++); // added ()
  3978. else
  3979. ptr ++;
  3980. }
  3981. } // for (ptr = tp ...)
  3982. // Now that we have scanned the entire table,
  3983. // adjust the table and cell widths to fit on the screen
  3984. if (numcells == 0) return endp;
  3985. // colspan widths
  3986. for (col = 0; col < numcells; col ++)
  3987. {
  3988. if (colspans[col] > 0) { // check width of colspans
  3989. colspanw = colspans[col]; // colspan width
  3990. colspan = colspans[col + 1]; // colspan
  3991. for (ti = col; ti < col + colspan; ti ++)
  3992. mincellw += mincols[ti]; // total width of mincols
  3993. if (colspans[col] > mincellw) { // pad columns with colspans
  3994. for (ti = col, maxcellw = 0; ti < col + colspan; ti ++) {
  3995. if (maxcols[ti] == 0) maxcols[ti] = 1; // set min width
  3996. maxcellw += maxcols[ti]; // total width of cells
  3997. colspanw -= mincols[ti]; // colspans remainder width
  3998. }
  3999. if (!maxcellw) maxcellw = 1; // avoid divide by zero
  4000. for (ti = col; ti < col + colspan; ti ++) {
  4001. tempw = (maxcols[ti] * 100) / maxcellw; // as percent
  4002. scalew = (colspanw * tempw) / 100; // as value
  4003. maxcols[ti] = mincols[ti] + scalew;
  4004. }
  4005. }
  4006. col += colspan - 1; // skip past colspan
  4007. }
  4008. }
  4009. // get min width of table from colspans
  4010. for (col = 0, mincellw = 0; col < numcells; col ++) {
  4011. if (colspans[col] > 0) {
  4012. mincellw += colspans[col]; // min table width
  4013. col += colspans[col + 1] - 1; // skip past colspan
  4014. }
  4015. else
  4016. mincellw += mincols[col];
  4017. }
  4018. if (mincellw > hwidth) { // if table wider than window
  4019. tsize = mincellw;
  4020. tsize += 6 * numcells;
  4021. tsize += xx + 4; // add 4 pixels in case width is hsize_
  4022. if (tsize > hsize_) tsize = hsize_;
  4023. }
  4024. else
  4025. tsize = hwidth;
  4026. tw = 0; // Reset
  4027. if (get_attr(tp + 6, "WIDTH", attr, sizeof(attr)))
  4028. tw = get_length(attr, tsize - xx);
  4029. //printf("numcells = %d, tw = %d, tsize = %d\n", numcells, tw, tsize);
  4030. if (tw == 0) // get max table width
  4031. maxlinew = tsize - xx;
  4032. else
  4033. maxlinew = tw;
  4034. maxlinew -= 6 * numcells; // sub internal borders
  4035. tw -= 6 * numcells;
  4036. if (tsize > hwidth) { // if table wider than window sub 4 pixels
  4037. maxlinew -= 4; // this is needed
  4038. tw -= 4;
  4039. }
  4040. if (tw < 0) tw = 0;
  4041. //printf(" tw = %d, maxlinew = %d, xx = %d, hsize_ = %d, mincellw = %d\n",
  4042. // tw, maxlinew, xx, hsize_, mincellw);
  4043. if (mincellw > maxlinew) // resize if colspans too wide
  4044. tw = mincellw + xx;
  4045. for (col = 0, linew = 0; col < numcells; col ++)
  4046. linew += maxcols[col]; // Add up the widths
  4047. if (!linew) linew = 1; // avoid divide by zero
  4048. //for (col = 0; col < numcells; col ++)
  4049. // printf(" maxcols[%d] = %d, mincols[%d] = %d, widths[%d] = %d, colspans[%d] = %d\n",
  4050. // col, maxcols[col], col, mincols[col],
  4051. // col, widths[col], col, colspans[col]);
  4052. //printf("linew = %d, w() = %d\n", linew, w());
  4053. scalew = tw;
  4054. if (tw == 0) { // Adjust the width if needed
  4055. if (linew > maxlinew)
  4056. scalew = maxlinew;
  4057. else
  4058. scalew = linew;
  4059. }
  4060. if (linew < scalew) // Table width is too small
  4061. {
  4062. //printf("Scaling table up to scalew %d from linew %d\n", scalew, linew);
  4063. scalew -= linew; // get remainder width
  4064. //printf("adjusted scalew = %d\n", scalew);
  4065. // scale table up
  4066. for (col = 0; col < numcells; col ++) {
  4067. tempw = (maxcols[col] * 100) / linew; // as percent
  4068. maxcols[col] += (tempw * scalew) / 100; // as value
  4069. }
  4070. // td widths
  4071. for (col = 0, ti = 0, tempw = 0; col < numcells; col ++) {
  4072. if (widths[col] > 0 && mincols[col] > widths[col]) {
  4073. tempw += maxcols[col] - mincols[col]; // remainder
  4074. maxcols[col] = mincols[col]; // set to minwidth
  4075. }
  4076. if (!widths[col]) ti ++; // unspecified widths
  4077. }
  4078. if (!ti) ti = 1; // avoid divide by zero
  4079. for (col = 0; col < numcells; col ++) {
  4080. if (!widths[col])
  4081. maxcols[col] += tempw / ti; // add remainder fractions
  4082. }
  4083. }
  4084. else if (linew > scalew) // Table width is too big
  4085. {
  4086. //printf("Scaling table down to scalew %d from linew %d\n", scalew, linew);
  4087. for (col = 0; col < numcells; col ++) {
  4088. linew -= mincols[col];
  4089. scalew -= mincols[col];
  4090. }
  4091. if (!linew) linew = 1; // avoid divide by zero
  4092. //printf("adjusted linew = %d, scalew = %d\n", linew, scalew);
  4093. for (col = 0; col < numcells; col ++) {
  4094. maxcols[col] -= mincols[col];
  4095. maxcols[col] = scalew * maxcols[col] / linew;
  4096. maxcols[col] += mincols[col];
  4097. }
  4098. }
  4099. else if (tw == 0) // Not sure if this is needed
  4100. tw = linew;
  4101. if (tw == 0) // tw still zero
  4102. for (col = 0; col < numcells; col ++)
  4103. tw += maxcols[col];
  4104. for (col = 0, maxcellw = 0; col < numcells; col ++)
  4105. maxcellw += maxcols[col]; // total width of cells
  4106. if (tw > maxcellw) { // add remainder to last column
  4107. tempw = tw - maxcellw;
  4108. maxcols[numcells - 1] += tempw;
  4109. }
  4110. //printf("FINAL tw = %d\n", tw);
  4111. //for (col = 0; col < numcells; col ++)
  4112. // printf(" maxcols[%d] = %d\n", col, maxcols[col]);
  4113. return endp; // table end pointer
  4114. } // Fl_Help_View::format_table()
  4115. //
  4116. // Fl_Help_View::free_data() - Free memory used for the document.
  4117. //
  4118. void Fl_Help_View::free_data()
  4119. {
  4120. if (value_) // Release all images
  4121. {
  4122. const char *ptr, // Pointer into block
  4123. *attrptr; // Start of attributes ptr
  4124. char *sp, // Pointer into buffer
  4125. buf[1024], // Text buffer
  4126. attr[1024], // Attribute buffer
  4127. wattr[1024], // Width attribute buffer
  4128. hattr[1024]; // Height attribute buffer
  4129. Fl_Shared_Image *img = 0; // Shared image - rem'd NULL
  4130. int imgw = 0, // Image width
  4131. imgh = 0; // Image height
  4132. for (ptr = value_; *ptr; )
  4133. {
  4134. if (*ptr == '<')
  4135. {
  4136. ptr ++;
  4137. if (!strncmp(ptr, "!--", 3)) { // Found "!--"
  4138. ptr += 3;
  4139. if ((ptr = strstr(ptr, "-->"))) { // Skip comment - rem'd != 0
  4140. ptr += 3;
  4141. continue;
  4142. }
  4143. else
  4144. break;
  4145. }
  4146. sp = buf;
  4147. while (*ptr && *ptr != '>' && !isspace((*ptr) & 255))
  4148. if (sp < (buf + sizeof(buf) - 1))
  4149. *(sp ++) = *(ptr ++); // added ()
  4150. else
  4151. ptr ++;
  4152. *sp = '\0'; // Nul-terminate
  4153. attrptr = ptr; // Start of attributes
  4154. while (*ptr && *ptr != '>') ptr ++;
  4155. if (*ptr == '>') ptr ++;
  4156. if (!strcasecmp(buf, "IMG"))
  4157. {
  4158. imgw = imgh = 0; // reset
  4159. if (get_attr(attrptr, "WIDTH", wattr, sizeof(wattr)))
  4160. imgw = get_length(wattr);
  4161. if (get_attr(attrptr, "HEIGHT", hattr, sizeof(hattr)))
  4162. imgh = get_length(hattr);
  4163. img = 0; // rem'd NULL
  4164. if (get_attr(attrptr, "SRC", attr, sizeof(attr)))
  4165. { // Release the image twice to free it from memory
  4166. img = get_image(attr, imgw, imgh);
  4167. // Seb was here - freeing a broken_image causes an XFreePixmap crash
  4168. if((void*)img != &broken_image) {
  4169. img->release();
  4170. if(img->refcount() > 0) img->release();
  4171. }
  4172. }
  4173. }
  4174. } // if (*ptr == '<')
  4175. else
  4176. ptr ++;
  4177. } // for (ptr = value_ ...)
  4178. free((void *)value_);
  4179. value_ = 0; // reset
  4180. } // if (value_)
  4181. if (!d->isnew) { // is new page
  4182. free((void *)d->csstext); // values
  4183. free((void *)d->cssword);
  4184. free((void *)d->cssurl);
  4185. d->csstext = 0;
  4186. d->cssword = 0;
  4187. d->cssurl = 0;
  4188. d->cssurllen = 0; // lengths
  4189. d->csswordlen = 0;
  4190. d->csstextlen = 0;
  4191. serifont_ = FL_TIMES; // default font
  4192. }
  4193. d->isnew = 1; // set
  4194. // Free all of the arrays
  4195. if (nblocks_) { // Free blocks
  4196. free(blocks_);
  4197. ablocks_ = 0;
  4198. nblocks_ = 0;
  4199. blocks_ = 0;
  4200. }
  4201. if (nlinks_) { // Free links
  4202. free(links_);
  4203. alinks_ = 0;
  4204. nlinks_ = 0;
  4205. links_ = 0;
  4206. }
  4207. if (ntargets_) { // Free targets
  4208. free(d->targets);
  4209. atargets_ = 0;
  4210. ntargets_ = 0;
  4211. d->targets = 0;
  4212. }
  4213. } // Fl_Help_View::free_data()
  4214. //
  4215. // Fl_Help_View::get_align() - Get an alignment attribute.
  4216. //
  4217. int // O - Alignment
  4218. Fl_Help_View::get_align(const char *ap, // I - Start of attrs pointer
  4219. int da) // I - Default alignment
  4220. {
  4221. char buf[255]; // Alignment value
  4222. if (!get_attr(ap, "ALIGN", buf, sizeof(buf))) // rem'd == 0
  4223. return da; // no align attribute
  4224. if (!strcasecmp(buf, "CENTER"))
  4225. return CENTER; // 0
  4226. else if (!strcasecmp(buf, "RIGHT"))
  4227. return RIGHT; // -1
  4228. else
  4229. return LEFT; // 1
  4230. } // Fl_Help_View::get_align()
  4231. //
  4232. // Fl_Help_View::get_attr() - Get an attribute value from the string.
  4233. //
  4234. const char * // O - Pointer to buf or NULL
  4235. Fl_Help_View::get_attr(const char *ap, // I - Start of attributes pointer
  4236. const char *np, // I - Name of attribute
  4237. char *buf, // O - Buffer for attribute value
  4238. int sb) // I - Sizeof buf
  4239. {
  4240. char name[255], // Name from string
  4241. *ptr, // Pointer into name or value
  4242. quote; // Quote char
  4243. buf[0] = '\0';
  4244. while (*ap && *ap != '>')
  4245. {
  4246. while (isspace((*ap) & 255)) ap ++;
  4247. if (*ap == '>' || !*ap) return 0; // rem'd NULL
  4248. for (ptr = name; *ap && !isspace((*ap) & 255) && *ap != '=' && *ap != '>'; )
  4249. if (ptr < (name + sizeof(name) - 1)) // Read in the attribute name
  4250. *(ptr ++) = *(ap ++); // added ()
  4251. else
  4252. ap ++;
  4253. *ptr = '\0';
  4254. if (isspace((*ap) & 255) || !*ap || *ap == '>')
  4255. buf[0] = '\0';
  4256. else
  4257. {
  4258. if (*ap == '=') ap ++;
  4259. for (ptr = buf; *ap && !isspace((*ap) & 255) && *ap != '>'; )
  4260. if (*ap == '\'' || *ap == '\"') { // Read in the attribute value
  4261. quote = *(ap ++); // added () same as quote=*ap;ap++;
  4262. while (*ap && *ap != quote)
  4263. if ((ptr - buf + 1) < sb) // Sizeof buf
  4264. *(ptr ++) = *(ap ++); // added () same as *ptr=*ap;ptr++;ap++;
  4265. else
  4266. ap ++;
  4267. if (*ap == quote) ap ++;
  4268. }
  4269. else if ((ptr - buf + 1) < sb) // Sizeof buf
  4270. *(ptr ++) = *(ap ++); // added ()
  4271. else
  4272. ap ++;
  4273. *ptr = '\0';
  4274. }
  4275. if (!strcasecmp(np, name)) // Name of attribute matches
  4276. return buf;
  4277. else
  4278. buf[0] = '\0';
  4279. if (*ap == '>') return 0; // rem'd NULL
  4280. } // while (*ap ...)
  4281. return 0; // rem'd NULL
  4282. } // Fl_Help_View::get_attr()
  4283. //
  4284. // Fl_Help_View::get_color() - Get an alignment attribute.
  4285. //
  4286. Fl_Color // O - Color value
  4287. Fl_Help_View::get_color(const char *np, // I - Color name
  4288. Fl_Color dc) // I - Default color value
  4289. {
  4290. int ti = 0, // Looping var
  4291. rgb = 0,
  4292. red = 0,
  4293. green = 0,
  4294. blue = 0, // RGB values
  4295. temp = 0; // temp var
  4296. static const struct { // Color name table
  4297. const char *name;
  4298. int r,
  4299. g,
  4300. b; // Red, green, blue
  4301. }
  4302. colors[] = {
  4303. { "black", 0x00, 0x00, 0x00 },
  4304. { "red", 0xff, 0x00, 0x00 },
  4305. { "green", 0x00, 0x80, 0x00 },
  4306. { "yellow", 0xff, 0xff, 0x00 },
  4307. { "blue", 0x00, 0x00, 0xff },
  4308. { "magenta", 0xff, 0x00, 0xff },
  4309. { "fuchsia", 0xff, 0x00, 0xff },
  4310. { "cyan", 0x00, 0xff, 0xff },
  4311. { "aqua", 0x00, 0xff, 0xff },
  4312. { "white", 0xff, 0xff, 0xff },
  4313. { "gray", 0x80, 0x80, 0x80 },
  4314. { "grey", 0x80, 0x80, 0x80 },
  4315. { "lime", 0x00, 0xff, 0x00 },
  4316. { "maroon", 0x80, 0x00, 0x00 },
  4317. { "navy", 0x00, 0x00, 0x80 },
  4318. { "olive", 0x80, 0x80, 0x00 },
  4319. { "purple", 0x80, 0x00, 0x80 },
  4320. { "silver", 0xc0, 0xc0, 0xc0 },
  4321. { "teal", 0x00, 0x80, 0x80 }
  4322. };
  4323. if (!np || !np[0]) return dc; // No name
  4324. if (np[0] != '#') // check no hash
  4325. for (ti = 0, rgb = 0; np[ti] != '\0'; ti ++) {
  4326. if (isalpha(np[ti])) rgb |= 1; // name if 1
  4327. if (isdigit(np[ti])) rgb |= 2; // decimal if 2
  4328. if (rgb == 3) break; // hex with no hash
  4329. }
  4330. if (np[0] == '#' || rgb == 3) // Do hex color lookup
  4331. {
  4332. if (rgb == 3) temp = 0; else temp = 1; // set name offset
  4333. rgb = strtol(np + temp, 0, 16); // rem'd NULL
  4334. if (strlen(np) > 4) { // 24-bit
  4335. red = rgb >> 16;
  4336. green = (rgb >> 8) & 255;
  4337. blue = rgb & 255;
  4338. }
  4339. else { // 16-bit?
  4340. red = (rgb >> 8) * 17;
  4341. green = ((rgb >> 4) & 15) * 17;
  4342. blue = (rgb & 15) * 17;
  4343. }
  4344. return fl_rgb_color((uchar)red, (uchar)green, (uchar)blue);
  4345. }
  4346. else // Do color name lookup
  4347. {
  4348. temp = sizeof(colors) / sizeof(colors[0]);
  4349. for (ti = 0; ti < temp; ti ++)
  4350. if (!strcasecmp(np, colors[ti].name)) {
  4351. return fl_rgb_color(colors[ti].r, colors[ti].g, colors[ti].b);
  4352. }
  4353. return dc; // Color not found
  4354. }
  4355. } // Fl_Help_View::get_color()
  4356. //
  4357. // Fl_Help_View::get_css_value() - Outputs the value of a given css property to buffer.
  4358. //
  4359. int // O - true if value exists, false otherwise
  4360. Fl_Help_View::get_css_value(const char *sp, // I - selector
  4361. const char *pp, // I - property
  4362. char *vp) // O - value
  4363. {
  4364. int ti = 0,
  4365. tj = 0,
  4366. tk = 0,
  4367. tword = 0,
  4368. tcount = 0, // temp vars
  4369. issel = 0,
  4370. isblock = 0,
  4371. isclass = 0,
  4372. order = 0, // misc vars
  4373. si = 0,
  4374. slen = 0,
  4375. plen = 0,
  4376. blen = 0,
  4377. vlen = 0;
  4378. char *tp = 0; // ptr
  4379. if (strchr(pp, '-')) blen = strchr(pp, '-') - pp; // base property length
  4380. plen = strlen(pp); // property length
  4381. slen = strlen(sp); // selector length
  4382. if (strstr(sp, ".")) isclass = 1; // class ptr
  4383. while (tk < 2) { // find selector
  4384. for (ti = 0; ti < d->csswordlen; ti ++) { // word loop
  4385. tword = *(d->cssword + ti); // word offset
  4386. tp = d->csstext + tword; // word ptr
  4387. if (isblock && *tp == '}') { issel = 0; isblock = 0; break; } // close block
  4388. if (isblock) {
  4389. if (!strncasecmp(tp, pp, plen)) { // full property
  4390. for (tj = *(d->cssword + ti + 1); tcount < 255; tj ++) { // value is next word
  4391. if (*(d->csstext + tj) == ';') break; // end of value
  4392. else {
  4393. *(vp + tcount) = *(d->csstext + tj); // copy value
  4394. tcount ++; // count word length
  4395. }
  4396. }
  4397. *(vp + tcount) = '\0'; // nul-terminate
  4398. return 1; // success
  4399. }
  4400. else if (blen) { // base property
  4401. if (!strncasecmp(tp, pp, blen) && !si) si = ti; // store index
  4402. }
  4403. }
  4404. if (issel && *tp == '{') isblock = 1; // open block
  4405. if (!isblock && !strncasecmp(tp, sp, slen)) {
  4406. if (isclass) // source has class
  4407. issel = 2; // found match
  4408. else if (*(tp + slen) != '.')
  4409. issel = 1; // match if target no class
  4410. }
  4411. }
  4412. if (!issel && isclass) { // class not found, find selector
  4413. slen = strstr(sp, ".") - sp; // remove class name
  4414. isclass = 0; // reset
  4415. }
  4416. tk ++; // second try without class name
  4417. }
  4418. if (si) { // found base but not full property
  4419. for (tj = *(d->cssword + si + 1); tcount < 255; tj ++) { // value is next word
  4420. if (*(d->csstext + tj) == ';') break; // end of value
  4421. else {
  4422. *(vp + tcount) = *(d->csstext + tj); // copy value
  4423. if (isspace(*(vp + tcount))) *(vp + tcount) = '\0'; // split words
  4424. tcount ++; // count word length
  4425. }
  4426. }
  4427. *(vp + tcount) = '\0'; // nul-terminate
  4428. for (tj = 0, ti = 0; tj < tcount; tj ++) { // shorthand recognition rules
  4429. if (*(vp + tj) == '\0') ti = 0; else ti ++;
  4430. if (ti == 1) { // first letter of word
  4431. vlen = strlen(vp + tj); // word length
  4432. if (!strncasecmp(pp, "background", 10)) // background shorthand
  4433. {
  4434. if (!strncasecmp(vp + tj, "none", 4) ||
  4435. !strncasecmp(vp + tj, "left", 4) ||
  4436. !strncasecmp(vp + tj, "right", 5) ||
  4437. !strncasecmp(vp + tj, "inherit", 7)) order = 0; // nothing
  4438. else if (*(vp + tj) == '#' ||
  4439. !strncasecmp(vp + tj, "rgb", 3) ||
  4440. !strncasecmp(vp + tj, "transparent", 11)) order = 1; // color
  4441. else if (!strncasecmp(vp + tj, "url", 3)) order = 2; // image
  4442. else if (!strncasecmp(vp + tj, "repeat", 6) ||
  4443. !strncasecmp(vp + tj, "no-repeat", 9)) order = 3; // repeat
  4444. else if (!strncasecmp(vp + tj, "scroll", 6) ||
  4445. !strncasecmp(vp + tj, "fixed", 5)) order = 4; // attachment
  4446. else if (isdigit(*(vp + tj)) ||
  4447. !strncasecmp(vp + tj, "top", 3) ||
  4448. !strncasecmp(vp + tj, "center", 6) ||
  4449. !strncasecmp(vp + tj, "bottom", 6)) { // position
  4450. // todo: count words to ; if one then replace \0 with ' ' - or just replace next '\0'
  4451. order = 5; }
  4452. else if (!strncasecmp(vp + tj, "black", 5) ||
  4453. !strncasecmp(vp + tj, "red", 3) ||
  4454. !strncasecmp(vp + tj, "green", 5) ||
  4455. !strncasecmp(vp + tj, "yellow", 6) ||
  4456. !strncasecmp(vp + tj, "blue", 4) ||
  4457. !strncasecmp(vp + tj, "magenta", 7) ||
  4458. !strncasecmp(vp + tj, "fuchsia", 7) ||
  4459. !strncasecmp(vp + tj, "cyan", 4) ||
  4460. !strncasecmp(vp + tj, "aqua", 4) ||
  4461. !strncasecmp(vp + tj, "white", 5) ||
  4462. !strncasecmp(vp + tj, "gray", 4) ||
  4463. !strncasecmp(vp + tj, "grey", 4) ||
  4464. !strncasecmp(vp + tj, "lime", 4) ||
  4465. !strncasecmp(vp + tj, "maroon", 6) ||
  4466. !strncasecmp(vp + tj, "navy", 4) ||
  4467. !strncasecmp(vp + tj, "olive", 5) ||
  4468. !strncasecmp(vp + tj, "purple", 6) ||
  4469. !strncasecmp(vp + tj, "silver", 6) ||
  4470. !strncasecmp(vp + tj, "teal", 4)) order = 1; // color name
  4471. if (!strncmp(pp, "background-color", 16) && order == 1) break;
  4472. if (!strncmp(pp, "background-image", 16) && order == 2) break;
  4473. if (!strncmp(pp, "background-repeat", 17) && order == 3) break;
  4474. if (!strncmp(pp, "background-attachment", 21) && order == 4) break;
  4475. if (!strncmp(pp, "background-position", 19) && order == 5) break;
  4476. order = 0; // reset
  4477. }
  4478. else if (!strncasecmp(pp, "border", 6)) // border shorthand
  4479. {
  4480. // todo: border-width-style-color
  4481. }
  4482. else if (!strncasecmp(pp, "font", 4)) // font shorthand
  4483. {
  4484. if (isdigit(*(vp + tj))) { // number
  4485. if (vlen == 3 && isdigit(*(vp + tj + 2))) order = 3; // weight
  4486. else order = 4; // size
  4487. }
  4488. else if (isalpha(*(vp + tj))) { // word
  4489. if (!strncasecmp(vp + tj, "normal", 6) ||
  4490. !strncasecmp(vp + tj, "lighter", 7) || // weight
  4491. !strncasecmp(vp + tj, "inherit", 7)) order = 0; // nothing
  4492. else if (!strncasecmp(vp + tj, "italic", 6) ||
  4493. !strncasecmp(vp + tj, "oblique", 7)) order = 1; // style
  4494. else if (!strncasecmp(vp + tj, "small-caps", 10)) order = 2; // variant
  4495. else if (!strncasecmp(vp + tj, "bold", 4)) order = 3; // weight
  4496. else if (!strncasecmp(vp + tj, "x-", 2) ||
  4497. !strncasecmp(vp + tj, "xx-", 3) ||
  4498. !strncasecmp(vp + tj, "small", 5) ||
  4499. !strncasecmp(vp + tj, "medium", 6) ||
  4500. !strncasecmp(vp + tj, "large", 5)) order = 4; // size
  4501. else order = 5; // family
  4502. }
  4503. if (!strncmp(pp, "font-style", 10) && order == 1) break;
  4504. if (!strncmp(pp, "font-variant", 12) && order == 2) break;
  4505. if (!strncmp(pp, "font-weight", 11) && order == 3) break;
  4506. if (!strncmp(pp, "font-size", 9) && order == 4) break;
  4507. if (!strncmp(pp, "font-family", 11) && order == 5) break;
  4508. order = 0; // reset
  4509. }
  4510. else if (!strncasecmp(pp, "margin", 6) ||
  4511. !strncasecmp(pp, "padding", 7)) // margin/padding shorthand
  4512. {
  4513. // todo: margin-top-right-bottom-left - padding has same keywords
  4514. }
  4515. else if (!strncasecmp(pp, "outline", 7)) // outline shorthand
  4516. {
  4517. // todo: outline-color-style-width
  4518. }
  4519. }
  4520. }
  4521. if (order && tj) { // copy word to start of buffer
  4522. for (ti = 0; ti < vlen; ti ++) *(vp + ti) = *(vp + tj + ti);
  4523. *(vp + vlen) = '\0'; // nul-terminate
  4524. }
  4525. return 1; // success
  4526. }
  4527. return 0; // failure
  4528. } // Fl_Help_View::get_css_value
  4529. //
  4530. // Fl_Help_View::get_font_size() - Get a height value for font-size.
  4531. //
  4532. int // O - height value
  4533. Fl_Help_View::get_font_size(const char *hp) // I - height pointer
  4534. {
  4535. int ti = 0, // temp var
  4536. upos = 0, // unit position - %,in,cm,mm,em,ex,pt,pc,px
  4537. slen = 0, // src length
  4538. val = 0; // integer value
  4539. char buf[8]; // buffer
  4540. if (!hp || !hp[0]) return 0; // no height
  4541. slen = strlen(hp);
  4542. if (slen > 8) slen = 8; // max length
  4543. for (val = 0; val < slen; val ++) {
  4544. if (isalpha(*(hp + val)) || *(hp + val) == '%') {
  4545. upos = val;
  4546. break; // unit position
  4547. }
  4548. }
  4549. if (!upos) val = slen; // no unit
  4550. for (ti = 0; ti < val; ti ++)
  4551. buf[ti] = *(hp + ti); // copy value to buffer
  4552. val = atoi(buf); // to int
  4553. if (*(hp + upos) == '%') { // percent
  4554. if (val > 100) val = 100;
  4555. else if (val < 0) val = 0;
  4556. val = (val * fontsize_) / 100;
  4557. }
  4558. else if (!strncmp(hp + upos, "em", 2)) // em
  4559. val = val * fontsize_;
  4560. else if (!strncasecmp(hp + upos, "ex", 2)) // ex
  4561. val = fontsize_ / val;
  4562. // note: pt, pica, cm, mm, in are all relative to screen size
  4563. // currently they equate to px - http://hsivonen.iki.fi/units
  4564. if (val > 48) val = 48; // max
  4565. else if (val < 8) val = 8; // min
  4566. return val;
  4567. } // Fl_Help_View::get_font_size()
  4568. //
  4569. // Fl_Help_View::get_image() - Get an inline image.
  4570. //
  4571. Fl_Shared_Image * // O - Image pointer
  4572. Fl_Help_View::get_image(const char *np, // Image filename
  4573. int iw, // Image width
  4574. int ih) // Image height
  4575. {
  4576. const char *namep; // Local filename
  4577. char dir[1024], // Current directory
  4578. temp[1024], // Temporary filename
  4579. *tptr,
  4580. *dirp; // Pointer into temporary name
  4581. Fl_Shared_Image *imgp; // Image pointer
  4582. // See if the image can be found
  4583. if (strchr(directory_, ':') && !strchr(np, ':')) // rem'd != 0 and == 0
  4584. { // dir has ':' char and np doesn't
  4585. if (np[0] == '/') { // Has sub-path
  4586. strlcpy(temp, directory_, sizeof(temp));
  4587. if ((tptr = strrchr(strchr(temp, ':') + 3, '/')) != 0) // get filename
  4588. strlcpy(tptr, np, sizeof(temp)-(tptr - temp)); // remove filename
  4589. else
  4590. strlcat(temp, np, sizeof(temp));
  4591. }
  4592. else // Just filename
  4593. snprintf(temp, sizeof(temp), "%s/%s", directory_, np);
  4594. if (link_)
  4595. namep = (*link_)(this, temp, 0);
  4596. else
  4597. namep = temp;
  4598. }
  4599. else if (np[0] != '/' && !strchr(np, ':')) // rem'd == 0
  4600. {
  4601. if (directory_[0])
  4602. snprintf(temp, sizeof(temp), "%s/%s", directory_, np);
  4603. else {
  4604. dirp = getcwd(dir, sizeof(dir)); // getcwd can fail and return wrong dir, bug?
  4605. snprintf(temp, sizeof(temp), "%s/%s", dir, np); // No end '/' char from getcwd
  4606. }
  4607. if (link_)
  4608. namep = (*link_)(this, temp, 0);
  4609. else
  4610. namep = temp;
  4611. }
  4612. else if (link_)
  4613. namep = (*link_)(this, np, 0);
  4614. else
  4615. namep = np;
  4616. //if (namep) printf(" get_image namep=(%s)\n",namep);
  4617. //printf(" get_image d->path=(%s)\n",d->path);
  4618. if (d->ispath) { // path is used
  4619. strlcpy(temp, d->path, sizeof(temp));
  4620. if ((tptr = strrchr(temp, '/'))) // tptr valid, add filename
  4621. strlcpy(tptr + 1, np, sizeof(temp)-(tptr + 1 - temp));
  4622. namep = temp;
  4623. }
  4624. if (!namep) return 0;
  4625. if (!strncmp(namep, "file:", 5)) namep += 5; // Adjust for file:
  4626. if (!(imgp = Fl_Shared_Image::get(namep, iw, ih))) // rem'd == 0
  4627. imgp = (Fl_Shared_Image *)&broken_image;
  4628. return imgp;
  4629. } // Fl_Help_View::get_image()
  4630. //
  4631. // Fl_Help_View::get_length() - Get a length value either absolute or %.
  4632. //
  4633. int // O - Length value
  4634. Fl_Help_View::get_length(const char *lp) // I - Length pointer
  4635. {
  4636. int val = 0; // Integer value
  4637. if (!lp || !lp[0]) return 0; // No length
  4638. val = atoi(lp);
  4639. if (lp[strlen(lp) - 1] == '%') { // Calc percent
  4640. if (val > 100) val = 100;
  4641. else if (val < 0) val = 0;
  4642. val = val * (hsize_ - (scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size())) / 100; // val from hsize_
  4643. }
  4644. return val;
  4645. } // Fl_Help_View::get_length()
  4646. //
  4647. // Fl_Help_View::get_length() - Get a length value of a given width.
  4648. //
  4649. int // O - Length value
  4650. Fl_Help_View::get_length(const char *lp, // I - Length pointer
  4651. int hw) // I - horizontal width
  4652. {
  4653. int val = 0; // Integer value
  4654. if (!lp || !lp[0]) return 0; // No length
  4655. val = atoi(lp);
  4656. if (lp[strlen(lp) - 1] == '%') { // Calc percent
  4657. if (val > 100) val = 100;
  4658. else if (val < 0) val = 0;
  4659. val = val * hw / 100; // get value from hw
  4660. }
  4661. return val;
  4662. } // Fl_Help_View::get_length()
  4663. //
  4664. // Fl_Help_View::gettopline() - Get current topline in document.
  4665. //
  4666. int Fl_Help_View::gettopline() // O - Current topline
  4667. {
  4668. return d->top;
  4669. }
  4670. //
  4671. // Fl_Help_View::handle() - Handle events in the widget.
  4672. //
  4673. int // O - True if we handled it, false otherwise
  4674. Fl_Help_View::handle(int event) // I - Event to handle
  4675. {
  4676. int xx = 0,
  4677. yy = 0, // Mouse positions
  4678. hh = 0; // window height
  4679. Fl_Boxtype bt = (box()) ? box() : FL_DOWN_BOX; // Box type
  4680. xx = Fl::event_x() - x() + leftline_; // Get mouse
  4681. yy = Fl::event_y() - y() + topline_;
  4682. if (d->resized && !Fl::event_buttons()) { // mouse up outside window
  4683. d->resized = 0; // reset d->resized
  4684. format(); // make sure text is wrapped to window
  4685. }
  4686. switch (event)
  4687. {
  4688. case FL_FOCUS: // Set keyboard focus
  4689. redraw(); // Set widget to draw
  4690. return 1;
  4691. case FL_UNFOCUS: // Reset keyboard focus
  4692. clear_selection(); // Clear text selection
  4693. redraw(); // Set widget to draw
  4694. return 1;
  4695. case FL_ENTER : // Mouse pointer entered widget
  4696. Fl_Group::handle(event);
  4697. return 1;
  4698. case FL_LEAVE : // Mouse pointer left widget
  4699. d->top = topline(); // set top
  4700. fl_cursor(FL_CURSOR_DEFAULT); // Default icon, usually arrow
  4701. break;
  4702. case FL_MOVE: // Mouse pointer was moved with no button pushed
  4703. hh = h() + topline_ - Fl::box_dy(bt); // get bottom of window
  4704. if (hscrollbar_.visible()) hh -= (scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size());
  4705. if (yy > hh) hh = -1; // mouse over hscrollbar so no active link
  4706. if (find_link(xx, yy) && hh > 0) // mouse y in bounds
  4707. fl_cursor(FL_CURSOR_HAND); // Hand icon
  4708. else
  4709. fl_cursor(FL_CURSOR_DEFAULT);
  4710. return 1;
  4711. case FL_PUSH: // Mouse button was pushed
  4712. if (Fl_Group::handle(event)) return 1;
  4713. d->linkp = find_link(xx, yy);
  4714. if (d->linkp) {
  4715. d->ispush = 1; // set link is pushed
  4716. fl_cursor(FL_CURSOR_HAND);
  4717. return 1;
  4718. }
  4719. if (begin_selection()) {
  4720. fl_cursor(FL_CURSOR_INSERT); // I-beam icon
  4721. return 1;
  4722. }
  4723. fl_cursor(FL_CURSOR_DEFAULT);
  4724. return 1;
  4725. case FL_DRAG: // Mouse pointer was moved with button pushed
  4726. if (d->ispush) { // link is pushed
  4727. if (Fl::event_is_click()) {
  4728. fl_cursor(FL_CURSOR_HAND);
  4729. } else {
  4730. fl_cursor(FL_CURSOR_DEFAULT); // Should be "FL_CURSOR_CANCEL" if we had it
  4731. }
  4732. return 1;
  4733. }
  4734. if (current_view == this && selection_push_last) {
  4735. if (extend_selection()) redraw(); // Set widget to draw
  4736. fl_cursor(FL_CURSOR_INSERT);
  4737. return 1;
  4738. }
  4739. fl_cursor(FL_CURSOR_DEFAULT);
  4740. return 1;
  4741. case FL_RELEASE: // Mouse button was released
  4742. if (d->ispush) { // link is pushed
  4743. if (Fl::event_is_click()) {
  4744. d->top = topline(); // set top
  4745. d->islink = 1; // set islink
  4746. follow_link(d->linkp);
  4747. }
  4748. fl_cursor(FL_CURSOR_DEFAULT);
  4749. d->ispush = 0; // reset link is pushed - was d->linkp = 0;
  4750. return 1;
  4751. }
  4752. if (current_view == this && selection_push_last) {
  4753. end_selection();
  4754. return 1;
  4755. }
  4756. return 1;
  4757. case FL_SHORTCUT: { // Shortcut key was pushed
  4758. char ascii = Fl::event_text()[0];
  4759. switch (ascii) {
  4760. case CTRL('A'): select_all(); redraw(); return 1; // Set widget to draw
  4761. case CTRL('C'):
  4762. case CTRL('X'): end_selection(1); return 1;
  4763. }
  4764. break; }
  4765. }
  4766. return Fl_Group::handle(event);
  4767. } // Fl_Help_View::handle()
  4768. //
  4769. // Fl_Help_View::hv_draw() - Draws text.
  4770. //
  4771. // Note: This function must be optimized for speed!
  4772. void Fl_Help_View::hv_draw(const char *tp, // I - Text to draw
  4773. int xx, // I - X position of text
  4774. int yy) // I - Y position of text
  4775. {
  4776. int width = 0, // Width of text
  4777. first = 0, // First selected position
  4778. last = 0; // Last selected position
  4779. if (selected && current_view == this &&
  4780. current_pos < selection_last &&
  4781. current_pos >= selection_first) { // Selected text
  4782. Fl_Color clr = fl_color();
  4783. fl_color(hv_selection_color);
  4784. width = (int)fl_width(tp);
  4785. if (current_pos + (int)strlen(tp) < selection_last)
  4786. width += (int)fl_width(" ");
  4787. fl_rectf(xx, yy + fl_descent() - fl_height(), width, fl_height());
  4788. fl_color(hv_selection_text_color);
  4789. fl_draw(tp, xx, yy);
  4790. fl_color(clr);
  4791. }
  4792. else { // Normal text
  4793. fl_draw(tp, xx, yy);
  4794. }
  4795. if (draw_mode) // Text is being selected
  4796. {
  4797. width = (int)fl_width(tp);
  4798. if (mouse_x >= xx && mouse_x < xx + width) {
  4799. if (mouse_y >= yy - fl_height() + fl_descent() &&
  4800. mouse_y <= yy + fl_descent()) {
  4801. first = current_pos;
  4802. // use 'quote_char' to calculate true length of HTML string
  4803. last = first + strlen(tp);
  4804. if (draw_mode == 1) { // Begin selection mode
  4805. selection_push_first = first;
  4806. selection_push_last = last;
  4807. }
  4808. else { // End selection mode
  4809. selection_drag_first = first;
  4810. selection_drag_last = last;
  4811. }
  4812. }
  4813. }
  4814. }
  4815. } // Fl_Help_View::hv_draw()
  4816. //
  4817. // Fl_Help_View::leftline() - Set the left line position.
  4818. //
  4819. void Fl_Help_View::leftline(int xx) // I - Left line position
  4820. {
  4821. if (!value_) return;
  4822. int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size();
  4823. if (hsize_ < w() - scrollsize || xx < 0)
  4824. xx = 0;
  4825. else if (xx > hsize_)
  4826. xx = hsize_;
  4827. leftline_ = xx;
  4828. hscrollbar_.value(leftline_, w() - scrollsize, 0, hsize_);
  4829. redraw(); // Set widget to draw
  4830. } // Fl_Help_View::leftline()
  4831. //
  4832. // Fl_Help_View::load() - Load the specified file.
  4833. //
  4834. int // O - 0 on success, -1 on error
  4835. Fl_Help_View::load(const char *fp) // I - File to load, may have target
  4836. {
  4837. FILE *filep; // File to read from
  4838. size_t fsize; // file size
  4839. long len = 0; // Length of file
  4840. char *target, // Target in file
  4841. *slash; // Directory separator
  4842. const char *namep; // Local filename
  4843. char error[1024], // Error buffer
  4844. newname[1024]; // New filename buffer
  4845. clear_selection(); // Clear text selection
  4846. strlcpy(newname, fp, sizeof(newname));
  4847. if ((target = strrchr(newname, '#'))) // Last '#' char - rem'd != 0
  4848. *(target ++) = '\0'; // Remove target - added ()
  4849. if (link_)
  4850. namep = (*link_)(this, newname, 0); // Link transform
  4851. else
  4852. namep = filename_; // Current filename
  4853. //printf(" load namep=(%s) d->nstyle=%d\n",namep,d->nstyle);
  4854. if (!(d->nstyle & HV_NONAVIGATE)) // user navigation, continue load
  4855. namep = newname;
  4856. if (!newname[0]) // avoid error
  4857. strlcpy(newname, "(null)", sizeof(newname));
  4858. if (!namep) return -1; // No file was loaded, fail
  4859. if (!strncmp(newname, "ftp:", 4) || !strncmp(newname, "http:", 5) ||
  4860. !strncmp(newname, "https:", 6) || !strncmp(newname, "ipp:", 4) ||
  4861. !strncmp(newname, "mailto:", 7) || !strncmp(newname, "news:", 5))
  4862. return -1; // last path is remote link, fail
  4863. if (!d->ispath) { // path not used
  4864. strlcpy(d->lpath, filename_, sizeof(d->lpath)); // last path
  4865. strlcpy(filename_, newname, sizeof(filename_)); // dir + filename
  4866. strlcpy(directory_, newname, sizeof(directory_)); // dir only
  4867. }
  4868. // Note: We do not support Windows backslashes,
  4869. // since they are illegal in URLs
  4870. if (!(slash = strrchr(directory_, '/'))) // rem'd == 0
  4871. directory_[0] = '\0'; // No '/' char
  4872. else if (slash > directory_ && slash[-1] != '/')
  4873. *slash = '\0'; // Remove filename, assumes filename exists
  4874. //if (value_) { free((void *)value_); value_ = 0; } // rem'd
  4875. free_data(); // free last document
  4876. if (!strncmp(namep, "ftp:", 4) || !strncmp(namep, "http:", 5) ||
  4877. !strncmp(namep, "https:", 6) || !strncmp(namep, "ipp:", 4) ||
  4878. !strncmp(namep, "mailto:", 7) || !strncmp(namep, "news:", 5))
  4879. { // Remote link
  4880. snprintf(error, sizeof(error),
  4881. "<HTML><HEAD><TITLE>Error - %s</TITLE></HEAD>"
  4882. "<BODY><H2>Error - %s</H2>"
  4883. "<P>Unable to find the address at <A HREF=\"%s\">%s</A></P>"
  4884. "<P><LI>No handler exists for this URI scheme</LI></P>",
  4885. strerror(errno), strerror(errno), namep, namep);
  4886. value_ = strdup(error); // Duplicate
  4887. }
  4888. else // Local link
  4889. {
  4890. if (!strncmp(namep, "file:", 5)) namep += 5; // Adjust for file:
  4891. if ((filep = fopen(namep, "rb"))) { // Binary - rem'd != 0
  4892. fseek(filep, 0, SEEK_END);
  4893. len = ftell(filep);
  4894. rewind(filep); // like fseek(fp, 0, SEEK_SET)
  4895. value_ = (const char *)calloc(len + 1, 1); // malloc but zero'd
  4896. fsize = fread((void *)value_, 1, len, filep);
  4897. fclose(filep);
  4898. }
  4899. else { // File not opened
  4900. snprintf(error, sizeof(error),
  4901. "<HTML><HEAD><TITLE>Error - File not found</TITLE></HEAD>"
  4902. "<BODY><H2>Error - File not found</H2>"
  4903. "<P>Unable to find the file at %s</P>"
  4904. "<P><LI><A HREF=\"javascript:history.back()\">Back</A></LI></P>",
  4905. namep);
  4906. value_ = strdup(error); // Duplicate
  4907. }
  4908. }
  4909. //printf(" load d->ltop=%d d->top=%d topline()=%d\n",d->ltop,d->top,topline());
  4910. if (!(!(d->nstyle & HV_NONAVIGATE) && d->isnav) && d->islink)
  4911. d->ltop = d->top; // leave if user nav and nav link, link clicked
  4912. format();
  4913. if (target) // Target in link
  4914. topline(target);
  4915. else
  4916. topline(0);
  4917. if (!(d->nstyle & HV_NONAVIGATE) && d->isnav) {
  4918. topline(d->ltop); // user navigation and is nav link
  4919. d->isnav = 0; // reset isnav
  4920. }
  4921. if (!strcmp(d->path, d->lpath)) topline(d->ltop); // remote link
  4922. if (d->islink) d->top = topline(); // link clicked, set top
  4923. leftline(0); // added
  4924. return 0; // File was loaded, success
  4925. } // Fl_Help_View::load()
  4926. //
  4927. // Fl_Help_View::load_css() - Loads a css file.
  4928. //
  4929. int // O - 0 if file loaded, -1 if error
  4930. Fl_Help_View::load_css(const char *fp) // I - file to load
  4931. {
  4932. FILE *filep; // file to read from
  4933. size_t fsize; // file size
  4934. int ti = 0,
  4935. tj = 0,
  4936. isblock = 0,
  4937. isstr = 0,
  4938. tcount = 0,
  4939. tstart = 0,
  4940. *tpi; // temp vars
  4941. long len = 0; // length of file
  4942. const char *namep; // local filename
  4943. char *tp; // temp ptr
  4944. namep = fp;
  4945. if (!namep) return -1; // no file handle, fail
  4946. if (!d->cssurl) { // first url
  4947. d->cssurllen = 1;
  4948. d->cssurl = (char *)calloc(1024, 1); // init zero'd
  4949. strlcpy(d->cssurl, namep, 1024);
  4950. }
  4951. else { // next url
  4952. for (ti = 0; ti < d->cssurllen; ti ++) {
  4953. tp = d->cssurl + (ti * 1024);
  4954. if (!strcmp(tp, namep)) len = 1; // url match
  4955. }
  4956. if (len != 1) { // no match, add new url
  4957. d->cssurl = (char *)realloc((void *)d->cssurl, (d->cssurllen + 1) * 1024);
  4958. tp = d->cssurl + (d->cssurllen * 1024);
  4959. strlcpy(tp, namep, 1024);
  4960. d->cssurllen ++;
  4961. }
  4962. }
  4963. if (len == 1) return -1; // url match, fail
  4964. if (!strncmp(namep, "ftp:", 4) || !strncmp(namep, "http:", 5) ||
  4965. !strncmp(namep, "https:", 6))
  4966. {
  4967. return -1; // remote link, fail
  4968. }
  4969. else // local link
  4970. {
  4971. if (!strncmp(namep, "file:", 5)) namep += 5; // adjust for file:
  4972. if ((filep = fopen(namep, "rb"))) { // binary - rem'd != 0
  4973. fseek(filep, 0, SEEK_END);
  4974. len = ftell(filep);
  4975. rewind(filep); // like fseek(fp, 0, SEEK_SET)
  4976. if (!d->csstext) { // first file
  4977. d->csstext = (char *)calloc(len + 1, 1); // init zero'd
  4978. tp = d->csstext;
  4979. d->csstextlen = len;
  4980. }
  4981. else { // next file
  4982. d->csstext = (char *)realloc((void *)d->csstext, d->csstextlen + len + 1);
  4983. tp = d->csstext + d->csstextlen;
  4984. tstart = d->csstextlen; // start of file
  4985. d->csstextlen += len; // total file length
  4986. }
  4987. *(tp + len) = '\0'; // nul-terminate file
  4988. fsize = fread((void *)tp, 1, len, filep);
  4989. fclose(filep);
  4990. for (ti = 0; ti < len; ti ++) { // count words
  4991. if (isspace(*(tp + ti))) tj = 0; // no word
  4992. else tj ++; // letter count
  4993. if (*(tp + ti) == '{') { tj = 1; isblock = 1; } // block
  4994. if (*(tp + ti) == '"') { if (isstr) isstr = 0; else isstr = 1; } // string
  4995. if (!isblock) { // outside block
  4996. if (*(tp + ti) == ',') { // special char
  4997. tj = 1; ti ++;
  4998. while (isspace(*(tp + ti)) && ti < len) ti ++; // skip space
  4999. }
  5000. }
  5001. else if (!isstr) { // inside block - ignore if in string
  5002. if (*(tp + ti) == ':' || *(tp + ti) == ';') { // special char
  5003. tj = 1; ti ++;
  5004. while (isspace(*(tp + ti)) && ti < len) ti ++; // skip space
  5005. }
  5006. }
  5007. if (*(tp + ti) == '}') { tj = 1; isblock = 0; } // block
  5008. if (tj == 1) tcount ++; // next word
  5009. if (*(tp + ti) == '{' || *(tp + ti) == '}') tj = 0; // single char word
  5010. }
  5011. if (!d->cssword) { // first file
  5012. d->cssword = (int *)calloc(tcount + 1, sizeof(int)); // init zero'd
  5013. tpi = d->cssword;
  5014. d->csswordlen = tcount;
  5015. }
  5016. else { // next file
  5017. d->cssword = (int *)realloc((void *)d->cssword, (d->csswordlen + tcount + 1) * sizeof(int));
  5018. tpi = d->cssword + d->csswordlen;
  5019. d->csswordlen += tcount; // total word count
  5020. }
  5021. *(tpi + tcount) = d->csstextlen; // set last int
  5022. for (ti = 0, isblock = 0, isstr = 0, tcount = 0; ti < len; ti ++) { // store word offsets
  5023. if (isspace(*(tp + ti))) tj = 0; // no word
  5024. else tj ++; // letter count
  5025. if (*(tp + ti) == '{') { tj = 1; isblock = 1; } // block
  5026. if (*(tp + ti) == '"') { if (isstr) isstr = 0; else isstr = 1; } // string
  5027. if (!isblock) { // outside block
  5028. if (*(tp + ti) == ',') { // special char
  5029. tj = 1; ti ++;
  5030. while (isspace(*(tp + ti)) && ti < len) ti ++; // skip space
  5031. }
  5032. }
  5033. else if (!isstr) { // inside block - ignore if in string
  5034. if (*(tp + ti) == ':' || *(tp + ti) == ';') { // special char
  5035. tj = 1; ti ++;
  5036. while (isspace(*(tp + ti)) && ti < len) ti ++; // skip space
  5037. }
  5038. }
  5039. if (*(tp + ti) == '}') { tj = 1; isblock = 0; } // block
  5040. if (tj == 1) {
  5041. *(tpi + tcount) = ti + tstart; // word offset
  5042. tcount ++; // next word
  5043. if (*(tp + ti) == '{' || *(tp + ti) == '}') tj = 0; // single char word
  5044. }
  5045. }
  5046. }
  5047. else
  5048. return -1; // file not opened, failure
  5049. }
  5050. return 0; // file was loaded, success
  5051. } // Fl_Help_View::load_css()
  5052. //
  5053. // Fl_Help_View::parse_css() - Parses all supported css properties.
  5054. //
  5055. void Fl_Help_View::parse_css(Fl_Help_Block &b, // O - current block
  5056. const char *sp, // I - selector ptr
  5057. char *buf) // O - text buffer
  5058. {
  5059. if (get_css_value(sp, "background-color", buf)) // background
  5060. b.bgcolor = get_color(buf, color());
  5061. // todo: image/repeat/attachment/position
  5062. if (get_css_value(sp, "font-family", buf)) // font
  5063. b.font = font_face(buf); // altered by style & weight
  5064. if (get_css_value(sp, "font-style", buf)) {
  5065. if (!strncasecmp(buf, "italic", 6) ||
  5066. !strncasecmp(buf, "oblique", 7))
  5067. b.font = font_style(b.font, FL_ITALIC);
  5068. }
  5069. if (get_css_value(sp, "font-weight", buf)) {
  5070. if (!strncasecmp(buf, "bold", 4))
  5071. b.font = font_style(b.font, FL_BOLD);
  5072. }
  5073. if (get_css_value(sp, "font-size", buf)) {
  5074. b.fsize = get_font_size(buf) + 2;
  5075. }
  5076. return;
  5077. } // Fl_Help_View::parse_css()
  5078. //
  5079. // Fl_Help_View::popfont() - Pop from font stack.
  5080. //
  5081. void Fl_Help_View::popfont(int &fi,
  5082. unsigned char &fs) { // pop font
  5083. if (d->nfonts > 0) d->nfonts --;
  5084. fl_font(fi = d->fonts[d->nfonts][0], fs = d->fonts[d->nfonts][1]);
  5085. }
  5086. //
  5087. // Fl_Help_View::pushfont() - Push to font stack.
  5088. //
  5089. void Fl_Help_View::pushfont(int fi,
  5090. unsigned char fs) { // push font
  5091. if (d->nfonts < 99) d->nfonts ++;
  5092. fl_font(d->fonts[d->nfonts][0] = fi, d->fonts[d->nfonts][1] = fs);
  5093. }
  5094. //
  5095. // Fl_Help_View::resize() - Resize the help widget.
  5096. //
  5097. void Fl_Help_View::resize(int xx, // I - New left position
  5098. int yy, // I - New top position
  5099. int ww, // I - New width
  5100. int hh) // I - New height
  5101. {
  5102. long time = 0,
  5103. sec = 0,
  5104. mil = 0; // timer vars
  5105. Fl_Boxtype bt = (box()) ? box() : FL_DOWN_BOX; // box to draw
  5106. Fl_Widget::resize(xx, yy, ww, hh); // Resize help widget
  5107. int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size();
  5108. scrollbar_.resize(x() + w() - scrollsize - Fl::box_dw(bt) + Fl::box_dx(bt),
  5109. y() + Fl::box_dy(bt), scrollsize, h() - scrollsize - Fl::box_dh(bt));
  5110. hscrollbar_.resize(x() + Fl::box_dx(bt),
  5111. y() + h() - scrollsize - Fl::box_dh(bt) + Fl::box_dy(bt),
  5112. w() - scrollsize - Fl::box_dw(bt), scrollsize);
  5113. // delay calls to format to avoid hangs on very large pages
  5114. if (abs(w() - d->rwidth) > 2) { // moved more than 2 pixels
  5115. fl_gettime(&sec, &mil); // find how long since last format
  5116. time = MIL(d->rsec, d->rmil, sec, mil);
  5117. if (time > d->rtime || !d->resized) { // enough time has passed
  5118. d->resized = 1; // set d->resized
  5119. format();
  5120. fl_gettime(&d->rsec, &d->rmil); // find how long this format took
  5121. d->rtime = MIL(d->rsec, d->rmil, sec, mil);
  5122. d->rtime /= 2; // wait half the time format took
  5123. d->rwidth = w(); // store window width
  5124. }
  5125. }
  5126. } // Fl_Help_View::resize()
  5127. //
  5128. // Fl_Help_View::select_all() - Select all text.
  5129. //
  5130. void Fl_Help_View::select_all()
  5131. {
  5132. clear_global_selection();
  5133. if (!value_) return;
  5134. current_view = this;
  5135. selection_drag_last = selection_last = strlen(value_);
  5136. selected = 1;
  5137. } // Fl_Help_View::select_all()
  5138. //
  5139. // Fl_Help_View::setstyle() - set the html style flag
  5140. //
  5141. void Fl_Help_View::setstyle(int flag) // I - style flag to set
  5142. {
  5143. d->nstyle = flag; // wasn't working as a method..
  5144. }
  5145. //
  5146. // Fl_Help_View::topline() - Set the top line to the named target.
  5147. //
  5148. void Fl_Help_View::topline(const char *np) // I - Target name
  5149. {
  5150. Fl_Help_Link key, // Target name key
  5151. *target; // Pointer to matching target
  5152. if (ntargets_ == 0) return;
  5153. strlcpy(key.name, np, sizeof(key.name));
  5154. target = (Fl_Help_Link *)bsearch(&key, d->targets, ntargets_,
  5155. sizeof(Fl_Help_Link),
  5156. (compare_func_t)cmp_targets);
  5157. if (target) topline(target->y); // Target found - rem'd != 0
  5158. } // Fl_Help_View::topline()
  5159. //
  5160. // Fl_Help_View::topline() - Set the top line by number.
  5161. //
  5162. void Fl_Help_View::topline(int yy) // I - Top line number
  5163. {
  5164. if (!value_) return;
  5165. int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size();
  5166. if (size_ < h() - scrollsize || yy < 0)
  5167. yy = 0;
  5168. else if (yy > size_)
  5169. yy = size_;
  5170. topline_ = yy;
  5171. scrollbar_.value(topline_, h() - scrollsize, 0, size_);
  5172. do_callback();
  5173. redraw(); // Set widget to draw
  5174. d->top = topline_; // set top
  5175. } // Fl_Help_View::topline()
  5176. //
  5177. // Fl_Help_View::value() - Set the help text directly.
  5178. //
  5179. // Note: called by nav buttons, also after follow_link
  5180. void Fl_Help_View::value(const char *tp) // I - Text to view
  5181. {
  5182. if (!tp) return; // Null
  5183. char target[32]; // current target
  5184. target[0] = '\0';
  5185. if (d->islink) { // link clicked
  5186. if (d->linkp) // link exists
  5187. strlcpy(target, d->linkp->name, sizeof(target));
  5188. d->islink = 0; // reset islink
  5189. if (!(d->nstyle & HV_NONAVIGATE)) return; // file was loaded
  5190. }
  5191. if (!tp[0]) { // text buffer empty
  5192. char error[1024]; // error buffer
  5193. const char *namep = 0; // local filename
  5194. if (d->ispath) namep = d->path; // path is used
  5195. else if (filename_[0]) namep = filename_;
  5196. if (!namep[0]) namep = "(null)";
  5197. if (!strncmp(namep, "ftp:", 4) || !strncmp(namep, "http:", 5) ||
  5198. !strncmp(namep, "https:", 6) || !strncmp(namep, "ipp:", 4) ||
  5199. !strncmp(namep, "mailto:", 7) || !strncmp(namep, "news:", 5)) {
  5200. snprintf(error, sizeof(error),
  5201. "<HTML><HEAD><TITLE>Error - Server not found</TITLE></HEAD>"
  5202. "<BODY><H2>Error - Server not found</H2>"
  5203. "<P>Unable to find the address at <A HREF=\"%s\">%s</A></P>"
  5204. "<P><LI>No handler exists for this URI scheme</LI></P>",
  5205. namep, namep);
  5206. }
  5207. else {
  5208. snprintf(error, sizeof(error),
  5209. "<HTML><HEAD><TITLE>Error - File not found</TITLE></HEAD>"
  5210. "<BODY><H2>Error - File not found</H2>"
  5211. "<P>Unable to find the file at %s</P>", namep);
  5212. if (d->lpath[0]) // last path exists
  5213. snprintf(error + strlen(error), sizeof(error) - strlen(error),
  5214. "<P><LI><A HREF=\"javascript:history.back()\">Back</A></P>");
  5215. }
  5216. clear_selection(); // clear text selection
  5217. set_changed(); // set widget value was changed
  5218. free_data(); // free last document
  5219. value_ = strdup(error); // duplicate
  5220. format();
  5221. topline(0);
  5222. leftline(0);
  5223. return; // we're done
  5224. }
  5225. //printf(" value target=(%s) d->ispath=%d\n",target,d->ispath);
  5226. //printf(" value d->path=(%s) d->islink=%d\n",d->path,d->islink);
  5227. clear_selection(); // Clear text selection
  5228. set_changed(); // Set widget value was changed
  5229. free_data(); // Free last document
  5230. value_ = strdup(tp); // Duplicate
  5231. if (d->islink) d->ltop = d->top; // link clicked, last top
  5232. format();
  5233. if (target[0]) // new link with target
  5234. topline(target); // set position on page
  5235. else // no target
  5236. topline(0);
  5237. if (d->islink) d->top = topline(); // link clicked, set top
  5238. leftline(0);
  5239. } // Fl_Help_View::value()
  5240. //
  5241. // Fl_Help_View::~Fl_Help_View() - Destroy a Fl_Help_View widget.
  5242. //
  5243. Fl_Help_View::~Fl_Help_View()
  5244. {
  5245. clear_selection(); // Clear text selection
  5246. free_data(); // Free last document
  5247. free(d); // free d-pointer
  5248. } // Fl_Help_View::~Fl_Help_View()
  5249. //
  5250. // 'command()' - Convert a command with up to four letters into an uint.
  5251. //
  5252. static unsigned int // O - Fourcc int
  5253. command(const char *cmdp) // I - Command pointer
  5254. {
  5255. unsigned int ret = (tolower(cmdp[0]) << 24);
  5256. char cc = cmdp[1];
  5257. if (cc == '>' || cc == ' ' || cc == 0) return ret;
  5258. ret |= (tolower(cc) << 16);
  5259. cc = cmdp[2];
  5260. if (cc == '>' || cc == ' ' || cc == 0) return ret;
  5261. ret |= (tolower(cc) << 8);
  5262. cc = cmdp[3];
  5263. if (cc == '>' || cc == ' ' || cc == 0) return ret;
  5264. ret |= tolower(cc);
  5265. cc = cmdp[4];
  5266. if (cc == '>' || cc == ' ' || cc == 0) return ret;
  5267. return 0;
  5268. } // command()
  5269. //
  5270. // 'quote_char()' - Return the character code associated with a quoted char.
  5271. //
  5272. static int // O - Code or -1 on error
  5273. quote_char(const char *qp, // I - Quoted string
  5274. int fc) // I - true to return what font char uses, opt
  5275. {
  5276. // updated table to HTML 4
  5277. // http://www.alanwood.net/demos/ansi.html
  5278. static struct
  5279. {
  5280. const char *name; // str pointer
  5281. int namelen, // str length
  5282. cdata, // character reference data
  5283. code, // ANSI/Unicode char code
  5284. mac, // Mac Roman char code
  5285. sym; // what font does char use? 0 = current, 1 = Symbol
  5286. }
  5287. *nameptr, // pointer into names array
  5288. names[] = // quoting names
  5289. {
  5290. //should be ordered for binary search
  5291. { "AElig;", 6, 198, 198, 174, ENC(0,0) }, // Latin capital AE
  5292. { "Aacute;", 7, 193, 193, 231, ENC(0,0) }, // Latin capital A acute
  5293. { "Acirc;", 6, 194, 194, 229, ENC(0,0) }, // Latin capital A circumflex
  5294. { "Agrave;", 7, 192, 192, 203, ENC(0,0) }, // Latin capital A grave
  5295. { "Alpha;", 6, 913, 'A', 'A', ENC(1,1) }, // Greek capital Alpha
  5296. { "Aring;", 6, 197, 197, 129, ENC(0,0) }, // Latin capital A ring above
  5297. { "Atilde;", 7, 195, 195, 204, ENC(0,0) }, // Latin capital A tilde
  5298. { "Auml;", 5, 196, 196, 128, ENC(0,0) }, // Latin capital A umlaut
  5299. { "Beta;", 5, 914, 'B', 'B', ENC(1,1) }, // Greek capital Beta
  5300. { "Ccedil;", 7, 199, 199, 130, ENC(0,0) }, // Latin capital C cedilla
  5301. { "Chi;", 4, 935, 'C', 'C', ENC(1,1) }, // Greek capital Chi
  5302. { "Dagger;", 7, 8225, 135, 224, ENC(0,0) }, // double dagger
  5303. { "Delta;", 6, 916, 'D', 'D', ENC(1,1) }, // Greek capital Delta
  5304. { "ETH;", 4, 208, 208, 198, ENC(0,1) }, // Latin capital ETH *
  5305. { "Eacute;", 7, 201, 201, 131, ENC(0,0) }, // Latin capital E acute
  5306. { "Ecirc;", 6, 202, 202, 230, ENC(0,0) }, // Latin capital E circumflex
  5307. { "Egrave;", 7, 200, 200, 233, ENC(0,0) }, // Latin capital E grave
  5308. { "Epsilon;",8, 917, 'E', 'E', ENC(1,1) }, // Greek capital Epsilon
  5309. { "Eta;", 4, 919, 'H', 'H', ENC(1,1) }, // Greek capital Eta
  5310. { "Euml;", 5, 203, 203, 232, ENC(0,0) }, // Latin capital E umlaut
  5311. { "Gamma;", 6, 915, 'G', 'G', ENC(1,1) }, // Greek capital Gamma
  5312. { "Iacute;", 7, 205, 205, 234, ENC(0,0) }, // Latin capital I acute
  5313. { "Icirc;", 6, 206, 206, 235, ENC(0,0) }, // Latin capital I circumflex
  5314. { "Igrave;", 7, 204, 204, 237, ENC(0,0) }, // Latin capital I grave
  5315. { "Iota;", 5, 921, 'I', 'I', ENC(1,1) }, // Greek capital Iota
  5316. { "Iuml;", 5, 207, 207, 236, ENC(0,0) }, // Latin capital I umlaut
  5317. { "Kappa;", 6, 922, 'K', 'K', ENC(1,1) }, // Greek capital Kappa
  5318. { "Lambda;", 7, 923, 'L', 'L', ENC(1,1) }, // Greek capital Lambda
  5319. { "Mu;", 3, 924, 'M', 'M', ENC(1,1) }, // Greek capital Mu
  5320. { "Ntilde;", 7, 209, 209, 132, ENC(0,0) }, // Latin capital N tilde
  5321. { "Nu;", 3, 925, 'N', 'N', ENC(1,1) }, // Greek capital Nu
  5322. { "OElig;", 6, 338, 140, 206, ENC(0,0) }, // Latin capital ligature OE
  5323. { "Oacute;", 7, 211, 211, 238, ENC(0,0) }, // Latin capital O acute
  5324. { "Ocirc;", 6, 212, 212, 239, ENC(0,0) }, // Latin capital O circumflex
  5325. { "Ograve;", 7, 210, 210, 241, ENC(0,0) }, // Latin capital O grave
  5326. { "Omega;", 6, 937, 'W', 'W', ENC(1,1) }, // Greek capital Omega # 189 in Mac Roman
  5327. { "Omicron;",8, 927, 'O', 'O', ENC(1,1) }, // Greek capital Omicron
  5328. { "Oslash;", 7, 216, 216, 175, ENC(0,0) }, // Latin capital O stroke
  5329. { "Otilde;", 7, 213, 213, 205, ENC(0,0) }, // Latin capital O tilde
  5330. { "Ouml;", 5, 214, 214, 133, ENC(0,0) }, // Latin capital O umlaut
  5331. { "Phi;", 4, 934, 'F', 'F', ENC(1,1) }, // Greek capital Phi
  5332. { "Pi;", 3, 928, 'P', 'P', ENC(1,1) }, // Greek capital Pi
  5333. { "Prime;", 6, 8243, 178, 178, ENC(1,1) }, // double prime
  5334. { "Psi;", 4, 936, 'Y', 'Y', ENC(1,1) }, // Greek capital Psi
  5335. { "Rho;", 4, 929, 'R', 'R', ENC(1,1) }, // Greek capital Rho
  5336. { "Scaron;", 7, 352, 138, 223, ENC(0,1) }, // Latin capital S caron *
  5337. { "Sigma;", 6, 931, 'S', 'S', ENC(1,1) }, // Greek capital Sigma
  5338. { "THORN;", 6, 222, 222, 167, ENC(0,1) }, // Latin capital THORN *
  5339. { "Tau;", 4, 932, 'T', 'T', ENC(1,1) }, // Greek capital Tau
  5340. { "Theta;", 6, 920, 'Q', 'Q', ENC(1,1) }, // Greek capital Theta
  5341. { "Uacute;", 7, 218, 218, 242, ENC(0,0) }, // Latin capital U acute
  5342. { "Ucirc;", 6, 219, 219, 243, ENC(0,0) }, // Latin capital U circumflex
  5343. { "Ugrave;", 7, 217, 217, 244, ENC(0,0) }, // Latin capital U grave
  5344. { "Upsilon;",8, 933, 'U', 'U', ENC(1,1) }, // Greek capital Upsilon
  5345. { "Uuml;", 5, 220, 220, 134, ENC(0,0) }, // Latin capital U umlaut
  5346. { "Xi;", 3, 926, 'X', 'X', ENC(1,1) }, // Greek capital Xi
  5347. { "Yacute;", 7, 221, 221, 217, ENC(0,1) }, // Latin capital Y acute *
  5348. { "Yuml;", 5, 376, 159, 217, ENC(0,0) }, // Latin capital Y umlaut
  5349. { "Zeta;", 5, 918, 'Z', 'Z', ENC(1,1) }, // Greek capital Zeta
  5350. { "aacute;", 7, 225, 225, 135, ENC(0,0) }, // Latin small a acute
  5351. { "acirc;", 6, 226, 226, 137, ENC(0,0) }, // Latin small a circumflex
  5352. { "acute;", 6, 180, 180, 171, ENC(0,0) }, // acute accent
  5353. { "aelig;", 6, 230, 230, 190, ENC(0,0) }, // Latin small ae
  5354. { "agrave;", 7, 224, 224, 136, ENC(0,0) }, // Latin small a grave
  5355. { "alefsym;",8, 8501, 192, 192, ENC(1,1) }, // alef symbol
  5356. { "alpha;", 6, 945, 'a', 'a', ENC(1,1) }, // Greek small alpha
  5357. { "amp;", 4, 38, '&', '&', ENC(0,0) }, // ampersand
  5358. { "and;", 4, 8743, 217, 217, ENC(1,1) }, // logical and
  5359. { "ang;", 4, 8736, 208, 208, ENC(1,1) }, // angle
  5360. { "aring;", 6, 229, 229, 140, ENC(0,0) }, // Latin small a ring above
  5361. { "asymp;", 6, 8776, 187, 197, ENC(1,0) }, // almost equal to #
  5362. { "atilde;", 7, 227, 227, 139, ENC(0,0) }, // Latin small a tilde
  5363. { "auml;", 5, 228, 228, 138, ENC(0,0) }, // Latin small a umlaut
  5364. { "bdquo;", 6, 8222, 132, 227, ENC(0,0) }, // double low-9 quotation mark
  5365. { "beta;", 5, 946, 'b', 'b', ENC(1,1) }, // Greek small beta
  5366. { "brvbar;", 7, 166, 166, 240, ENC(0,1) }, // broken bar *
  5367. { "bull;", 5, 8226, 183, 165, ENC(1,0) }, // bullet
  5368. { "cap;", 4, 8745, 199, 199, ENC(1,1) }, // intersection
  5369. { "ccedil;", 7, 231, 231, 141, ENC(0,0) }, // Latin small c cedilla
  5370. { "cedil;", 6, 184, 184, 252, ENC(0,0) }, // cedilla
  5371. { "cent;", 5, 162, 162, 162, ENC(0,0) }, // cent sign
  5372. { "chi;", 4, 967, 'c', 'c', ENC(1,1) }, // Greek small chi
  5373. { "circ;", 5, 710, 136, 246, ENC(0,0) }, // modifier circumflex accent
  5374. { "clubs;", 6, 9827, 167, 167, ENC(1,1) }, // black club suit
  5375. { "cong;", 5, 8773, '@', '@', ENC(1,1) }, // approximately equal to
  5376. { "copy;", 5, 169, 169, 169, ENC(0,0) }, // copyright sign
  5377. { "crarr;", 6, 8629, 191, 191, ENC(1,1) }, // carriage return arrow
  5378. { "cup;", 4, 8746, 200, 200, ENC(1,1) }, // union
  5379. { "curren;", 7, 164, 164, 251, ENC(0,1) }, // currency sign *
  5380. { "dArr;", 5, 8659, 223, 223, ENC(1,1) }, // down double arrow
  5381. { "dagger;", 7, 8224, 134, 160, ENC(0,0) }, // dagger
  5382. { "darr;", 5, 8595, 175, 175, ENC(1,1) }, // down arrow
  5383. { "deg;", 4, 176, 176, 161, ENC(0,0) }, // degree sign
  5384. { "delta;", 6, 948, 'd', 'd', ENC(1,1) }, // Greek small delta
  5385. { "diams;", 6, 9830, 168, 168, ENC(1,1) }, // black diamond suit
  5386. { "divide;", 7, 247, 247, 214, ENC(0,0) }, // division sign
  5387. { "eacute;", 7, 233, 233, 142, ENC(0,0) }, // Latin small e acute
  5388. { "ecirc;", 6, 234, 234, 144, ENC(0,0) }, // Latin small e circumflex
  5389. { "egrave;", 7, 232, 232, 143, ENC(0,0) }, // Latin small e grave
  5390. { "empty;", 6, 8709, 198, 198, ENC(1,1) }, // empty set
  5391. { "emsp;", 5, 8195, ' ', ' ', ENC(0,0) }, // em space - NA
  5392. { "ensp;", 5, 8194, ' ', ' ', ENC(0,0) }, // en space - NA
  5393. { "epsilon;",8, 949, 'e', 'e', ENC(1,1) }, // Greek small epsilon
  5394. { "equiv;", 6, 8801, 186, 186, ENC(1,1) }, // identical to
  5395. { "eta;", 4, 951, 'h', 'h', ENC(1,1) }, // Greek small eta
  5396. { "eth;", 4, 240, 240, 182, ENC(0,1) }, // Latin small eth *
  5397. { "euml;", 5, 235, 235, 145, ENC(0,0) }, // Latin small e umlaut
  5398. { "euro;", 5, 8364, 'C', 219, ENC(0,0) }, // euro sign
  5399. { "exist;", 6, 8707, '$', '$', ENC(1,1) }, // there exists
  5400. { "fnof;", 5, 402, 166, 196, ENC(1,0) }, // Latin small f hook
  5401. { "forall;", 7, 8704, '\"','\"',ENC(1,1) }, // for all
  5402. { "frac12;", 7, 189, 189, 255, ENC(0,1) }, // vulgar fraction 1/2 *
  5403. { "frac14;", 7, 188, 188, 254, ENC(0,1) }, // vulgar fraction 1/4 *
  5404. { "frac34;", 7, 190, 190, 250, ENC(0,1) }, // vulgar fraction 3/4 *
  5405. { "frasl;", 6, 8260, 164, 218, ENC(1,0) }, // fraction slash #
  5406. { "gamma;", 6, 947, 'g', 'g', ENC(1,1) }, // Greek small gamma
  5407. { "ge;", 3, 8805, 179, 179, ENC(1,0) }, // greater-than or equal to #
  5408. { "gt;", 3, 62, '>', '>', ENC(0,0) }, // greater-than sign
  5409. { "hArr;", 5, 8660, 219, 219, ENC(1,1) }, // horizontal double arrow
  5410. { "harr;", 5, 8596, 171, 171, ENC(1,1) }, // horizontal arrow
  5411. { "hearts;", 7, 9829, 169, 169, ENC(1,1) }, // black heart suit
  5412. { "hellip;", 7, 8230, 188, 201, ENC(1,0) }, // horizontal ellipsis
  5413. { "iacute;", 7, 237, 237, 146, ENC(0,0) }, // Latin small i acute
  5414. { "icirc;", 6, 238, 238, 148, ENC(0,0) }, // Latin small i circumflex
  5415. { "iexcl;", 6, 161, 161, 193, ENC(0,0) }, // inverted exclamation mark
  5416. { "igrave;", 7, 236, 236, 147, ENC(0,0) }, // Latin small i grave
  5417. { "image;", 6, 8465, 193, 193, ENC(1,1) }, // blackletter capital I, imaginary part
  5418. { "infin;", 6, 8734, 165, 176, ENC(1,0) }, // infinity #
  5419. { "int;", 4, 8747, 242, 186, ENC(1,0) }, // integral #
  5420. { "iota;", 5, 953, 'i', 'i', ENC(1,1) }, // Greek small iota
  5421. { "iquest;", 7, 191, 191, 192, ENC(0,0) }, // inverted question mark
  5422. { "isin;", 5, 8712, 206, 206, ENC(1,1) }, // element of
  5423. { "iuml;", 5, 239, 239, 149, ENC(0,0) }, // Latin small i umlaut
  5424. { "kappa;", 6, 954, 'k', 'k', ENC(1,1) }, // Greek small kappa
  5425. { "lArr;", 5, 8656, 220, 220, ENC(1,1) }, // left double arrow
  5426. { "lambda;", 7, 955, 'l', 'l', ENC(1,1) }, // Greek small lambda
  5427. { "lang;", 5, 9001, 225, 225, ENC(1,1) }, // left-pointing angle bracket
  5428. { "laquo;", 6, 171, 171, 199, ENC(0,0) }, // left double angle quotation
  5429. { "larr;", 5, 8592, 172, 172, ENC(1,1) }, // left arrow
  5430. { "lceil;", 6, 8968, 233, 233, ENC(1,1) }, // left ceiling
  5431. { "ldquo;", 6, 8220, 147, 210, ENC(0,0) }, // left double quotation mark
  5432. { "le;", 3, 8804, 163, 178, ENC(1,0) }, // less-than or equal to #
  5433. { "lfloor;", 7, 8970, 235, 235, ENC(1,1) }, // left floor
  5434. { "lowast;", 7, 8727, '*', '*', ENC(1,1) }, // asterisk operator
  5435. { "loz;", 4, 9674, 224, 215, ENC(1,0) }, // lozenge #
  5436. { "lrm;", 4, 8206, ' ', ' ', ENC(0,0) }, // left-to-right mark - NA
  5437. { "lsaquo;", 7, 8249, 225, 220, ENC(1,0) }, // single left angle quotation
  5438. { "lsquo;", 6, 8216, 145, 212, ENC(0,0) }, // left single quotation mark
  5439. { "lt;", 3, 60, '<', '<', ENC(0,0) }, // less-than sign
  5440. { "macr;", 5, 175, 175, 248, ENC(0,0) }, // macron
  5441. { "mdash;", 6, 8212, 190, 209, ENC(1,0) }, // em dash
  5442. { "micro;", 6, 181, 181, 181, ENC(0,0) }, // micro sign
  5443. { "middot;", 7, 183, 183, 225, ENC(0,0) }, // middle dot
  5444. { "minus;", 6, 8722, 190, 190, ENC(1,1) }, // minus sign
  5445. { "mu;", 3, 956, 'm', 'm', ENC(1,1) }, // Greek small mu
  5446. { "nabla;", 6, 8711, 209, 209, ENC(1,1) }, // nabla
  5447. { "nbsp;", 5, 160, ' ', ' ', ENC(0,0) }, // no-break space, 160/202
  5448. { "ndash;", 6, 8211, '-', 208, ENC(1,0) }, // en dash
  5449. { "ne;", 3, 8800, 185, 173, ENC(1,0) }, // not equal to #
  5450. { "ni;", 3, 8715, '\'','\'',ENC(1,1) }, // contains as member
  5451. { "not;", 4, 172, 172, 194, ENC(0,0) }, // not sign
  5452. { "notin;", 6, 8713, 207, 207, ENC(1,1) }, // not an element of
  5453. { "nsub;", 5, 8836, 203, 203, ENC(1,1) }, // not a subset of
  5454. { "ntilde;", 7, 241, 241, 150, ENC(0,0) }, // Latin small n tilde
  5455. { "nu;", 3, 957, 'n', 'n', ENC(1,1) }, // Greek small nu
  5456. { "oacute;", 7, 243, 243, 151, ENC(0,0) }, // Latin small o acute
  5457. { "ocirc;", 6, 244, 244, 153, ENC(0,0) }, // Latin small o circumflex
  5458. { "oelig;", 6, 339, 156, 207, ENC(0,0) }, // Latin small ligature oe
  5459. { "ograve;", 7, 242, 242, 152, ENC(0,0) }, // Latin small o grave
  5460. { "oline;", 6, 8254, '_', '_', ENC(1,1) }, // overline
  5461. { "omega;", 6, 969, 'w', 'w', ENC(1,1) }, // Greek small omega
  5462. { "omicron;",8, 959, 'o', 'o', ENC(1,1) }, // Greek small omicron
  5463. { "oplus;", 6, 8853, 197, 197, ENC(1,1) }, // circled plus
  5464. { "or;", 3, 8744, 218, 218, ENC(1,1) }, // logical or
  5465. { "ordf;", 5, 170, 170, 187, ENC(0,0) }, // feminine ordinal indicator
  5466. { "ordm;", 5, 186, 186, 188, ENC(0,0) }, // masculine ordinal indicator
  5467. { "oslash;", 7, 248, 248, 191, ENC(0,0) }, // Latin small o stroke
  5468. { "otilde;", 7, 245, 245, 155, ENC(0,0) }, // Latin small o tilde
  5469. { "otimes;", 7, 8855, 196, 196, ENC(1,1) }, // circled times
  5470. { "ouml;", 5, 246, 246, 154, ENC(0,0) }, // Latin small o umlaut
  5471. { "para;", 5, 182, 182, 166, ENC(0,0) }, // pilcrow sign
  5472. { "part;", 5, 8706, 182, 182, ENC(1,0) }, // partial differential #
  5473. { "permil;", 7, 8240, 137, 228, ENC(0,0) }, // per mille sign
  5474. { "perp;", 5, 8869, '^', '^', ENC(1,1) }, // up tack
  5475. { "phi;", 4, 966, 'j', 'j', ENC(1,1) }, // Greek small phi, 'f' is phi variant
  5476. { "pi;", 3, 960, 'p', 'p', ENC(1,1) }, // Greek small pi # 185 in Mac Roman
  5477. { "piv;", 4, 982, 'v', 'v', ENC(1,1) }, // Greek small pi variant
  5478. { "plusmn;", 7, 177, 177, 177, ENC(0,0) }, // plus-minus sign
  5479. { "pound;", 6, 163, 163, 163, ENC(0,0) }, // pound sign
  5480. { "prime;", 6, 8242, 162, 162, ENC(1,1) }, // prime
  5481. { "prod;", 5, 8719, 213, 184, ENC(1,0) }, // n-ary product #
  5482. { "prop;", 5, 8733, 181, 181, ENC(1,1) }, // proportional to
  5483. { "psi;", 4, 968, 'y', 'y', ENC(1,1) }, // Greek small psi
  5484. { "quot;", 5, 34, '\"','\"',ENC(0,0) }, // quotation mark
  5485. { "rArr;", 5, 8658, 222, 222, ENC(1,1) }, // right double arrow
  5486. { "radic;", 6, 8730, 214, 195, ENC(1,0) }, // square root #
  5487. { "rang;", 5, 9002, 241, 241, ENC(1,1) }, // right-pointing angle bracket
  5488. { "raquo;", 6, 187, 187, 200, ENC(0,0) }, // right double angle quotation
  5489. { "rarr;", 5, 8594, 174, 174, ENC(1,1) }, // right arrow
  5490. { "rceil;", 6, 8969, 249, 249, ENC(1,1) }, // right ceiling
  5491. { "rdquo;", 6, 8221, 148, 211, ENC(0,0) }, // right double quotation mark
  5492. { "real;", 5, 8476, 194, 194, ENC(1,1) }, // blackletter capital R, real part
  5493. { "reg;", 4, 174, 174, 168, ENC(0,0) }, // registered sign
  5494. { "rfloor;", 7, 8971, 251, 251, ENC(1,1) }, // right floor
  5495. { "rho;", 4, 961, 'r', 'r', ENC(1,1) }, // Greek small rho
  5496. { "rlm;", 4, 8207, ' ', ' ', ENC(0,0) }, // right-to-left mark - NA
  5497. { "rsaquo;", 7, 8250, 241, 221, ENC(1,0) }, // single right angle quotation
  5498. { "rsquo;", 6, 8217, 146, 213, ENC(0,0) }, // right single quotation mark
  5499. { "sbquo;", 6, 8218, 130, 226, ENC(0,0) }, // single low-9 quotation mark
  5500. { "scaron;", 7, 353, 154, 222, ENC(0,1) }, // Latin small s caron *
  5501. { "sdot;", 5, 8901, 215, 215, ENC(1,1) }, // dot operator
  5502. { "sect;", 5, 167, 167, 164, ENC(0,0) }, // section sign
  5503. { "shy;", 4, 173, 173, '-', ENC(0,0) }, // soft hyphen
  5504. { "sigma;", 6, 962, 's', 's', ENC(1,1) }, // Greek small sigma
  5505. { "sigmaf;", 7, 963, 'V', 'V', ENC(1,1) }, // Greek small sigma final variant
  5506. { "sim;", 4, 8764, '~', '~', ENC(1,1) }, // tilde operator
  5507. { "spades;", 7, 9824, 170, 170, ENC(1,1) }, // black spade suit
  5508. { "sub;", 4, 8834, 204, 204, ENC(1,1) }, // subset of
  5509. { "sube;", 5, 8838, 205, 205, ENC(1,1) }, // subset of or equal to
  5510. { "sum;", 4, 8721, 229, 183, ENC(1,0) }, // n-ary summation #
  5511. { "sup1;", 5, 185, 185, 245, ENC(0,1) }, // superscript one *
  5512. { "sup2;", 5, 178, 178, 253, ENC(0,1) }, // superscript two *
  5513. { "sup3;", 5, 179, 179, 249, ENC(0,1) }, // superscript three *
  5514. { "sup;", 4, 8835, 201, 201, ENC(1,1) }, // superset of
  5515. { "supe;", 5, 8839, 202, 202, ENC(1,1) }, // superset of or equal to
  5516. { "szlig;", 6, 223, 223, 167, ENC(0,0) }, // Latin small sharp s
  5517. { "tau;", 4, 964, 't', 't', ENC(1,1) }, // Greek small tau
  5518. { "there4;", 7, 8756, '\\','\\',ENC(1,1) }, // therefore
  5519. { "theta;", 6, 952, 'q', 'q', ENC(1,1) }, // Greek small theta
  5520. { "thetasym;",9, 977,'J', 'J', ENC(1,1) }, // Greek small theta variant
  5521. { "thinsp;", 7, 8201, ' ', ' ', ENC(0,0) }, // thin space - NA
  5522. { "thorn;", 6, 254, 254, 164, ENC(0,1) }, // Latin small thorn *
  5523. { "tilde;", 6, 732, 152, 247, ENC(0,0) }, // small tilde
  5524. { "times;", 6, 215, 215, 'x', ENC(0,0) }, // multiplication sign
  5525. { "trade;", 6, 8482, 228, 170, ENC(1,0) }, // trade mark sign
  5526. { "uArr;", 5, 8657, 221, 221, ENC(1,1) }, // up double arrow
  5527. { "uacute;", 7, 250, 250, 156, ENC(0,0) }, // Latin small u acute
  5528. { "uarr;", 5, 8593, 173, 173, ENC(1,1) }, // up arrow
  5529. { "ucirc;", 6, 251, 251, 158, ENC(0,0) }, // Latin small u circumflex
  5530. { "ugrave;", 7, 249, 249, 157, ENC(0,0) }, // Latin small u grave
  5531. { "uml;", 4, 168, 168, 172, ENC(0,0) }, // diaeresis/umlaut
  5532. { "upsih;", 6, 978, 161, 111, ENC(1,1) }, // Greek capital upsilon hook variant
  5533. { "upsilon;",8, 965, 'u', 'u', ENC(1,1) }, // Greek small upsilon
  5534. { "uuml;", 5, 252, 252, 159, ENC(0,0) }, // Latin small u umlaut
  5535. { "weierp;", 7, 8472, 195, 195, ENC(1,1) }, // script capital P, power set
  5536. { "xi;", 3, 958, 'x', 'x', ENC(1,1) }, // Greek small xi
  5537. { "yacute;", 7, 253, 253, 216, ENC(0,1) }, // Latin small y acute *
  5538. { "yen;", 4, 165, 165, 180, ENC(0,0) }, // yen sign
  5539. { "yuml;", 5, 255, 255, 216, ENC(0,0) }, // Latin small y umlaut
  5540. { "zeta;", 5, 950, 'z', 'z', ENC(1,1) }, // Greek small zeta
  5541. { "zwj;", 4, 8205, ' ', ' ', ENC(0,0) }, // zero width joiner - NA
  5542. { "zwnj;", 5, 8204, ' ', ' ', ENC(0,0) }, // nzero width non-joiner - NA
  5543. };
  5544. if (!strchr(qp, ';')) return -1; // No semi-colon char
  5545. int ifirst, ilast, temp;
  5546. ilast = ( int ) ( sizeof ( names ) / sizeof ( names[0] ) ) - 1; // array size / element size
  5547. if (*qp == '#') // Numeric character reference
  5548. {
  5549. if (*(qp + 1) == 'x' || *(qp + 1) == 'X') // Hexadecimal number
  5550. temp = strtol(qp + 2, 0, 16); // Base-16 str to long - rem'd NULL
  5551. else // Decimal number
  5552. temp = atoi(qp + 1); // Convert str to int
  5553. if (fc) // check font char arg
  5554. {
  5555. ifirst = 0;
  5556. while ( ifirst <= ilast )
  5557. {
  5558. int mid = ( ifirst + ilast ) / 2; // compute mid point.
  5559. nameptr = names + mid;
  5560. int icmp = strncmp ( qp, nameptr->name, nameptr->namelen );
  5561. if ( icmp > 0 )
  5562. ifirst = mid + 1; // repeat search in top half.
  5563. else if ( icmp < 0 )
  5564. ilast = mid - 1; // repeat search in bottom half.
  5565. else // found it. return
  5566. return nameptr->sym;
  5567. }
  5568. return 0; // cdata not found, use current font
  5569. }
  5570. return temp;
  5571. }
  5572. ifirst = 0;
  5573. while ( ifirst <= ilast )
  5574. {
  5575. int mid = ( ifirst + ilast ) / 2; // compute mid point.
  5576. nameptr = names + mid;
  5577. int icmp = strncmp ( qp, nameptr->name, nameptr->namelen );
  5578. if ( icmp > 0 )
  5579. ifirst = mid + 1; // repeat search in top half.
  5580. else if ( icmp < 0 )
  5581. ilast = mid - 1; // repeat search in bottom half.
  5582. else
  5583. {
  5584. // found it. return
  5585. if(fc) return nameptr->sym;
  5586. return ENC(nameptr->code, nameptr->mac);
  5587. }
  5588. }
  5589. return -1; // Entity character reference not found
  5590. } // quote_char()
  5591. //
  5592. // 'hscrollbar_callback()' - Callback for the horizontal scrollbar.
  5593. //
  5594. static void hscrollbar_callback(Fl_Widget *s, // I - Scrollbar handle
  5595. void *)
  5596. {
  5597. ((Fl_Help_View *)(s->parent()))->leftline(int(((Fl_Scrollbar*)s)->value()));
  5598. } // hscrollbar_callback()
  5599. //
  5600. // 'scrollbar_callback()' - Callback for the scrollbar.
  5601. //
  5602. static void scrollbar_callback(Fl_Widget *s, // I - Scrollbar handle
  5603. void *)
  5604. {
  5605. ((Fl_Help_View *)(s->parent()))->topline(int(((Fl_Scrollbar*)s)->value()));
  5606. } // scrollbar_callback()
  5607. //
  5608. // End of "$Id: Fl_Help_View.cxx 6091 2008-04-11 11:12:16Z matt $".
  5609. //