build.c 92 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <ctype.h>
  5. #include <html.h>
  6. #include "impl.h"
  7. // A stack for holding integer values
  8. enum {
  9. Nestmax = 40 // max nesting level of lists, font styles, etc.
  10. };
  11. struct Stack {
  12. int n; // next available slot (top of stack is stack[n-1])
  13. int slots[Nestmax]; // stack entries
  14. };
  15. // Parsing state
  16. struct Pstate
  17. {
  18. Pstate* next; // in stack of Pstates
  19. int skipping; // true when we shouldn't add items
  20. int skipwhite; // true when we should strip leading space
  21. int curfont; // font index for current font
  22. int curfg; // current foreground color
  23. Background curbg; // current background
  24. int curvoff; // current baseline offset
  25. uchar curul; // current underline/strike state
  26. uchar curjust; // current justify state
  27. int curanchor; // current (href) anchor id (if in one), or 0
  28. int curstate; // current value of item state
  29. int literal; // current literal state
  30. int inpar; // true when in a paragraph-like construct
  31. int adjsize; // current font size adjustment
  32. Item* items; // dummy head of item list we're building
  33. Item* lastit; // tail of item list we're building
  34. Item* prelastit; // item before lastit
  35. Stack fntstylestk; // style stack
  36. Stack fntsizestk; // size stack
  37. Stack fgstk; // text color stack
  38. Stack ulstk; // underline stack
  39. Stack voffstk; // vertical offset stack
  40. Stack listtypestk; // list type stack
  41. Stack listcntstk; // list counter stack
  42. Stack juststk; // justification stack
  43. Stack hangstk; // hanging stack
  44. };
  45. struct ItemSource
  46. {
  47. Docinfo* doc;
  48. Pstate* psstk;
  49. int nforms;
  50. int ntables;
  51. int nanchors;
  52. int nframes;
  53. Form* curform;
  54. Map* curmap;
  55. Table* tabstk;
  56. Kidinfo* kidstk;
  57. };
  58. // Some layout parameters
  59. enum {
  60. FRKIDMARGIN = 6, // default margin around kid frames
  61. IMGHSPACE = 0, // default hspace for images (0 matches IE, Netscape)
  62. IMGVSPACE = 0, // default vspace for images
  63. FLTIMGHSPACE = 2, // default hspace for float images
  64. TABSP = 5, // default cellspacing for tables
  65. TABPAD = 1, // default cell padding for tables
  66. LISTTAB = 1, // number of tabs to indent lists
  67. BQTAB = 1, // number of tabs to indent blockquotes
  68. HRSZ = 2, // thickness of horizontal rules
  69. SUBOFF = 4, // vertical offset for subscripts
  70. SUPOFF = 6, // vertical offset for superscripts
  71. NBSP = 160 // non-breaking space character
  72. };
  73. // These tables must be sorted
  74. static StringInt align_tab[] = {
  75. {L"baseline", ALbaseline},
  76. {L"bottom", ALbottom},
  77. {L"center", ALcenter},
  78. {L"char", ALchar},
  79. {L"justify", ALjustify},
  80. {L"left", ALleft},
  81. {L"middle", ALmiddle},
  82. {L"right", ALright},
  83. {L"top", ALtop}
  84. };
  85. #define NALIGNTAB (sizeof(align_tab)/sizeof(StringInt))
  86. static StringInt input_tab[] = {
  87. {L"button", Fbutton},
  88. {L"checkbox", Fcheckbox},
  89. {L"file", Ffile},
  90. {L"hidden", Fhidden},
  91. {L"image", Fimage},
  92. {L"password", Fpassword},
  93. {L"radio", Fradio},
  94. {L"reset", Freset},
  95. {L"submit", Fsubmit},
  96. {L"text", Ftext}
  97. };
  98. #define NINPUTTAB (sizeof(input_tab)/sizeof(StringInt))
  99. static StringInt clear_tab[] = {
  100. {L"all", IFcleft|IFcright},
  101. {L"left", IFcleft},
  102. {L"right", IFcright}
  103. };
  104. #define NCLEARTAB (sizeof(clear_tab)/sizeof(StringInt))
  105. static StringInt fscroll_tab[] = {
  106. {L"auto", FRhscrollauto|FRvscrollauto},
  107. {L"no", FRnoscroll},
  108. {L"yes", FRhscroll|FRvscroll},
  109. };
  110. #define NFSCROLLTAB (sizeof(fscroll_tab)/sizeof(StringInt))
  111. static StringInt shape_tab[] = {
  112. {L"circ", SHcircle},
  113. {L"circle", SHcircle},
  114. {L"poly", SHpoly},
  115. {L"polygon", SHpoly},
  116. {L"rect", SHrect},
  117. {L"rectangle", SHrect}
  118. };
  119. #define NSHAPETAB (sizeof(shape_tab)/sizeof(StringInt))
  120. static StringInt method_tab[] = {
  121. {L"get", HGet},
  122. {L"post", HPost}
  123. };
  124. #define NMETHODTAB (sizeof(method_tab)/sizeof(StringInt))
  125. static Rune* roman[15]= {
  126. L"I", L"II", L"III", L"IV", L"V", L"VI", L"VII", L"VIII", L"IX", L"X",
  127. L"XI", L"XII", L"XIII", L"XIV", L"XV"
  128. };
  129. #define NROMAN 15
  130. // List number types
  131. enum {
  132. LTdisc, LTsquare, LTcircle, LT1, LTa, LTA, LTi, LTI
  133. };
  134. enum {
  135. SPBefore = 2,
  136. SPAfter = 4,
  137. BL = 1,
  138. BLBA = (BL|SPBefore|SPAfter)
  139. };
  140. // blockbrk[tag] is break info for a block level element, or one
  141. // of a few others that get the same treatment re ending open paragraphs
  142. // and requiring a line break / vertical space before them.
  143. // If we want a line of space before the given element, SPBefore is OR'd in.
  144. // If we want a line of space after the given element, SPAfter is OR'd in.
  145. static uchar blockbrk[Numtags]= {
  146. [Taddress] BLBA, [Tblockquote] BLBA, [Tcenter] BL,
  147. [Tdir] BLBA, [Tdiv] BL, [Tdd] BL, [Tdl] BLBA,
  148. [Tdt] BL, [Tform] BLBA,
  149. // headings and tables get breaks added manually
  150. [Th1] BL, [Th2] BL, [Th3] BL,
  151. [Th4] BL, [Th5] BL, [Th6] BL,
  152. [Thr] BL, [Tisindex] BLBA, [Tli] BL, [Tmenu] BLBA,
  153. [Tol] BLBA, [Tp] BLBA, [Tpre] BLBA,
  154. [Tul] BLBA
  155. };
  156. enum {
  157. AGEN = 1
  158. };
  159. // attrinfo is information about attributes.
  160. // The AGEN value means that the attribute is generic (applies to almost all elements)
  161. static uchar attrinfo[Numattrs]= {
  162. [Aid] AGEN, [Aclass] AGEN, [Astyle] AGEN, [Atitle] AGEN,
  163. [Aonblur] AGEN, [Aonchange] AGEN, [Aonclick] AGEN,
  164. [Aondblclick] AGEN, [Aonfocus] AGEN, [Aonkeypress] AGEN,
  165. [Aonkeyup] AGEN, [Aonload] AGEN, [Aonmousedown] AGEN,
  166. [Aonmousemove] AGEN, [Aonmouseout] AGEN, [Aonmouseover] AGEN,
  167. [Aonmouseup] AGEN, [Aonreset] AGEN, [Aonselect] AGEN,
  168. [Aonsubmit] AGEN, [Aonunload] AGEN
  169. };
  170. static uchar scriptev[Numattrs]= {
  171. [Aonblur] SEonblur, [Aonchange] SEonchange, [Aonclick] SEonclick,
  172. [Aondblclick] SEondblclick, [Aonfocus] SEonfocus, [Aonkeypress] SEonkeypress,
  173. [Aonkeyup] SEonkeyup, [Aonload] SEonload, [Aonmousedown] SEonmousedown,
  174. [Aonmousemove] SEonmousemove, [Aonmouseout] SEonmouseout, [Aonmouseover] SEonmouseover,
  175. [Aonmouseup] SEonmouseup, [Aonreset] SEonreset, [Aonselect] SEonselect,
  176. [Aonsubmit] SEonsubmit, [Aonunload] SEonunload
  177. };
  178. // Color lookup table
  179. static StringInt color_tab[] = {
  180. {L"aqua", 0x00FFFF},
  181. {L"black", 0x000000},
  182. {L"blue", 0x0000CC},
  183. {L"fuchsia", 0xFF00FF},
  184. {L"gray", 0x808080},
  185. {L"green", 0x008000},
  186. {L"lime", 0x00FF00},
  187. {L"maroon", 0x800000},
  188. {L"navy", 0x000080,},
  189. {L"olive", 0x808000},
  190. {L"purple", 0x800080},
  191. {L"red", 0xFF0000},
  192. {L"silver", 0xC0C0C0},
  193. {L"teal", 0x008080},
  194. {L"white", 0xFFFFFF},
  195. {L"yellow", 0xFFFF00}
  196. };
  197. #define NCOLORS (sizeof(color_tab)/sizeof(StringInt))
  198. static StringInt *targetmap;
  199. static int targetmapsize;
  200. static int ntargets;
  201. static int buildinited = 0;
  202. #define SMALLBUFSIZE 240
  203. #define BIGBUFSIZE 2000
  204. int dbgbuild = 0;
  205. int warn = 0;
  206. static Align aalign(Token* tok);
  207. static int acolorval(Token* tok, int attid, int dflt);
  208. static void addbrk(Pstate* ps, int sp, int clr);
  209. static void additem(Pstate* ps, Item* it, Token* tok);
  210. static void addlinebrk(Pstate* ps, int clr);
  211. static void addnbsp(Pstate* ps);
  212. static void addtext(Pstate* ps, Rune* s);
  213. static Dimen adimen(Token* tok, int attid);
  214. static int aflagval(Token* tok, int attid);
  215. static int aintval(Token* tok, int attid, int dflt);
  216. static Rune* astrval(Token* tok, int attid, Rune* dflt);
  217. static int atabval(Token* tok, int attid, StringInt* tab, int ntab, int dflt);
  218. static int atargval(Token* tok, int dflt);
  219. static int auintval(Token* tok, int attid, int dflt);
  220. static Rune* aurlval(Token* tok, int attid, Rune* dflt, Rune* base);
  221. static Rune* aval(Token* tok, int attid);
  222. static void buildinit(void);
  223. static Pstate* cell_pstate(Pstate* oldps, int ishead);
  224. static void changehang(Pstate* ps, int delta);
  225. static void changeindent(Pstate* ps, int delta);
  226. static int color(Rune* s, int dflt);
  227. static void copystack(Stack* tostk, Stack* fromstk);
  228. static int dimprint(char* buf, int nbuf, Dimen d);
  229. static Pstate* finishcell(Table* curtab, Pstate* psstk);
  230. static void finish_table(Table* t);
  231. static void freeanchor(Anchor* a);
  232. static void freedestanchor(DestAnchor* da);
  233. static void freeform(Form* f);
  234. static void freeformfield(Formfield* ff);
  235. static void freeitem(Item* it);
  236. static void freepstate(Pstate* p);
  237. static void freepstatestack(Pstate* pshead);
  238. static void freescriptevents(SEvent* ehead);
  239. static void freetable(Table* t);
  240. static Map* getmap(Docinfo* di, Rune* name);
  241. static Rune* getpcdata(Token* toks, int tokslen, int* ptoki);
  242. static Pstate* lastps(Pstate* psl);
  243. static Rune* listmark(uchar ty, int n);
  244. static int listtyval(Token* tok, int dflt);
  245. static Align makealign(int halign, int valign);
  246. static Background makebackground(Rune* imgurl, int color);
  247. static Dimen makedimen(int kind, int spec);
  248. static Anchor* newanchor(int index, Rune* name, Rune* href, int target, Anchor* link);
  249. static Area* newarea(int shape, Rune* href, int target, Area* link);
  250. static DestAnchor* newdestanchor(int index, Rune* name, Item* item, DestAnchor* link);
  251. static Docinfo* newdocinfo(void);
  252. static Genattr* newgenattr(Rune* id, Rune* class, Rune* style, Rune* title, Attr* events);
  253. static Form* newform(int formid, Rune* name, Rune* action,
  254. int target, int method, Form* link);
  255. static Formfield* newformfield(int ftype, int fieldid, Form* form, Rune* name,
  256. Rune* value, int size, int maxlength, Formfield* link);
  257. static Item* newifloat(Item* it, int side);
  258. static Item* newiformfield(Formfield* ff);
  259. static Item* newiimage(Rune* src, Rune* altrep, int align, int width, int height,
  260. int hspace, int vspace, int border, int ismap, Map* map);
  261. static Item* newirule(int align, int size, int noshade, int color, Dimen wspec);
  262. static Item* newispacer(int spkind);
  263. static Item* newitable(Table* t);
  264. static ItemSource* newitemsource(Docinfo* di);
  265. static Item* newitext(Rune* s, int fnt, int fg, int voff, int ul);
  266. static Kidinfo* newkidinfo(int isframeset, Kidinfo* link);
  267. static Option* newoption(int selected, Rune* value, Rune* display, Option* link);
  268. static Pstate* newpstate(Pstate* link);
  269. static SEvent* newscriptevent(int type, Rune* script, SEvent* link);
  270. static Table* newtable(int tableid, Align align, Dimen width, int border,
  271. int cellspacing, int cellpadding, Background bg, Token* tok, Table* link);
  272. static Tablecell* newtablecell(int cellid, int rowspan, int colspan, Align align, Dimen wspec,
  273. int hspec, Background bg, int flags, Tablecell* link);
  274. static Tablerow* newtablerow(Align align, Background bg, int flags, Tablerow* link);
  275. static Dimen parsedim(Rune* s, int ns);
  276. static void pop(Stack* stk);
  277. static void popfontsize(Pstate* ps);
  278. static void popfontstyle(Pstate* ps);
  279. static void popjust(Pstate* ps);
  280. static int popretnewtop(Stack* stk, int dflt);
  281. static int push(Stack* stk, int val);
  282. static void pushfontsize(Pstate* ps, int sz);
  283. static void pushfontstyle(Pstate* ps, int sty);
  284. static void pushjust(Pstate* ps, int j);
  285. static Item* textit(Pstate* ps, Rune* s);
  286. static Rune* removeallwhite(Rune* s);
  287. static void resetdocinfo(Docinfo* d);
  288. static void setcurfont(Pstate* ps);
  289. static void setcurjust(Pstate* ps);
  290. static void setdimarray(Token* tok, int attid, Dimen** pans, int* panslen);
  291. static Rune* stringalign(int a);
  292. static void targetmapinit(void);
  293. static int toint(Rune* s);
  294. static int top(Stack* stk, int dflt);
  295. static void trim_cell(Tablecell* c);
  296. static int validalign(Align a);
  297. static int validdimen(Dimen d);
  298. static int validformfield(Formfield* f);
  299. static int validhalign(int a);
  300. static int validptr(void* p);
  301. static int validStr(Rune* s);
  302. static int validtable(Table* t);
  303. static int validtablerow(Tablerow* r);
  304. static int validtablecol(Tablecol* c);
  305. static int validtablecell(Tablecell* c);
  306. static int validvalign(int a);
  307. static int Iconv(Fmt *f);
  308. static void
  309. buildinit(void)
  310. {
  311. fmtinstall('I', Iconv);
  312. targetmapinit();
  313. buildinited = 1;
  314. }
  315. static ItemSource*
  316. newitemsource(Docinfo* di)
  317. {
  318. ItemSource* is;
  319. Pstate* ps;
  320. ps = newpstate(nil);
  321. if(di->mediatype != TextHtml) {
  322. ps->curstate &= ~IFwrap;
  323. ps->literal = 1;
  324. pushfontstyle(ps, FntT);
  325. }
  326. is = (ItemSource*)emalloc(sizeof(ItemSource));
  327. is->doc = di;
  328. is->psstk = ps;
  329. is->nforms = 0;
  330. is->ntables = 0;
  331. is->nanchors = 0;
  332. is->nframes = 0;
  333. is->curform = nil;
  334. is->curmap = nil;
  335. is->tabstk = nil;
  336. is->kidstk = nil;
  337. return is;
  338. }
  339. static Item *getitems(ItemSource* is, uchar* data, int datalen);
  340. // Parse an html document and create a list of layout items.
  341. // Allocate and return document info in *pdi.
  342. // When caller is done with the items, it should call
  343. // freeitems on the returned result, and then
  344. // freedocinfo(*pdi).
  345. Item*
  346. parsehtml(uchar* data, int datalen, Rune* pagesrc, int mtype, int chset, Docinfo** pdi)
  347. {
  348. Item *it;
  349. Docinfo* di;
  350. ItemSource* is;
  351. di = newdocinfo();
  352. di->src = _Strdup(pagesrc);
  353. di->base = _Strdup(pagesrc);
  354. di->mediatype = mtype;
  355. di->chset = chset;
  356. *pdi = di;
  357. is = newitemsource(di);
  358. it = getitems(is, data, datalen);
  359. freepstatestack(is->psstk);
  360. free(is);
  361. return it;
  362. }
  363. // Get a group of tokens for lexer, parse them, and create
  364. // a list of layout items.
  365. // When caller is done with the items, it should call
  366. // freeitems on the returned result.
  367. static Item*
  368. getitems(ItemSource* is, uchar* data, int datalen)
  369. {
  370. int i;
  371. int j;
  372. int nt;
  373. int pt;
  374. int doscripts;
  375. int tokslen;
  376. int toki;
  377. int h;
  378. int sz;
  379. int method;
  380. int n;
  381. int nblank;
  382. int norsz;
  383. int bramt;
  384. int sty;
  385. int nosh;
  386. int color;
  387. int oldcuranchor;
  388. int dfltbd;
  389. int v;
  390. int hang;
  391. int isempty;
  392. int tag;
  393. int brksp;
  394. int target;
  395. uchar brk;
  396. uchar flags;
  397. uchar align;
  398. uchar al;
  399. uchar ty;
  400. uchar ty2;
  401. Pstate* ps;
  402. Pstate* nextps;
  403. Pstate* outerps;
  404. Table* curtab;
  405. Token* tok;
  406. Token* toks;
  407. Docinfo* di;
  408. Item* ans;
  409. Item* img;
  410. Item* ffit;
  411. Item* tabitem;
  412. Rune* s;
  413. Rune* t;
  414. Rune* name;
  415. Rune* enctype;
  416. Rune* usemap;
  417. Rune* prompt;
  418. Rune* equiv;
  419. Rune* val;
  420. Rune* nsz;
  421. Rune* script;
  422. Map* map;
  423. Form* frm;
  424. Iimage* ii;
  425. Kidinfo* kd;
  426. Kidinfo* ks;
  427. Kidinfo* pks;
  428. Dimen wd;
  429. Option* option;
  430. Table* tab;
  431. Tablecell* c;
  432. Tablerow* tr;
  433. Formfield* field;
  434. Formfield* ff;
  435. Rune* href;
  436. Rune* src;
  437. Rune* scriptsrc;
  438. Rune* bgurl;
  439. Rune* action;
  440. Background bg;
  441. if(!buildinited)
  442. buildinit();
  443. doscripts = 0; // for now
  444. ps = is->psstk;
  445. curtab = is->tabstk;
  446. di = is->doc;
  447. toks = _gettoks(data, datalen, di->chset, di->mediatype, &tokslen);
  448. toki = 0;
  449. for(; toki < tokslen; toki++) {
  450. tok = &toks[toki];
  451. if(dbgbuild > 1)
  452. fprint(2, "build: curstate %ux, token %T\n", ps->curstate, tok);
  453. tag = tok->tag;
  454. brk = 0;
  455. brksp = 0;
  456. if(tag < Numtags) {
  457. brk = blockbrk[tag];
  458. if(brk&SPBefore)
  459. brksp = 1;
  460. }
  461. else if(tag < Numtags + RBRA) {
  462. brk = blockbrk[tag - RBRA];
  463. if(brk&SPAfter)
  464. brksp = 1;
  465. }
  466. if(brk) {
  467. addbrk(ps, brksp, 0);
  468. if(ps->inpar) {
  469. popjust(ps);
  470. ps->inpar = 0;
  471. }
  472. }
  473. // check common case first (Data), then switch statement on tag
  474. if(tag == Data) {
  475. // Lexing didn't pay attention to SGML record boundary rules:
  476. // \n after start tag or before end tag to be discarded.
  477. // (Lex has already discarded all \r's).
  478. // Some pages assume this doesn't happen in <PRE> text,
  479. // so we won't do it if literal is true.
  480. // BUG: won't discard \n before a start tag that begins
  481. // the next bufferful of tokens.
  482. s = tok->text;
  483. n = _Strlen(s);
  484. if(!ps->literal) {
  485. i = 0;
  486. j = n;
  487. if(toki > 0) {
  488. pt = toks[toki - 1].tag;
  489. // IE and Netscape both ignore this rule (contrary to spec)
  490. // if previous tag was img
  491. if(pt < Numtags && pt != Timg && j > 0 && s[0] == '\n')
  492. i++;
  493. }
  494. if(toki < tokslen - 1) {
  495. nt = toks[toki + 1].tag;
  496. if(nt >= RBRA && nt < Numtags + RBRA && j > i && s[j - 1] == '\n')
  497. j--;
  498. }
  499. if(i > 0 || j < n) {
  500. t = s;
  501. s = _Strsubstr(s, i, j);
  502. free(t);
  503. n = j-i;
  504. }
  505. }
  506. if(ps->skipwhite) {
  507. _trimwhite(s, n, &t, &nt);
  508. if(t == nil) {
  509. free(s);
  510. s = nil;
  511. }
  512. else if(t != s) {
  513. t = _Strndup(t, nt);
  514. free(s);
  515. s = t;
  516. }
  517. if(s != nil)
  518. ps->skipwhite = 0;
  519. }
  520. tok->text = nil; // token doesn't own string anymore
  521. if(s != nil)
  522. addtext(ps, s);
  523. }
  524. else
  525. switch(tag) {
  526. // Some abbrevs used in following DTD comments
  527. // %text = #PCDATA
  528. // | TT | I | B | U | STRIKE | BIG | SMALL | SUB | SUP
  529. // | EM | STRONG | DFN | CODE | SAMP | KBD | VAR | CITE
  530. // | A | IMG | APPLET | FONT | BASEFONT | BR | SCRIPT | MAP
  531. // | INPUT | SELECT | TEXTAREA
  532. // %block = P | UL | OL | DIR | MENU | DL | PRE | DL | DIV | CENTER
  533. // | BLOCKQUOTE | FORM | ISINDEX | HR | TABLE
  534. // %flow = (%text | %block)*
  535. // %body.content = (%heading | %text | %block | ADDRESS)*
  536. // <!ELEMENT A - - (%text) -(A)>
  537. // Anchors are not supposed to be nested, but you sometimes see
  538. // href anchors inside destination anchors.
  539. case Ta:
  540. if(ps->curanchor != 0) {
  541. if(warn)
  542. fprint(2, "warning: nested <A> or missing </A>\n");
  543. ps->curanchor = 0;
  544. }
  545. name = aval(tok, Aname);
  546. href = aurlval(tok, Ahref, nil, di->base);
  547. // ignore rel, rev, and title attrs
  548. if(href != nil) {
  549. target = atargval(tok, di->target);
  550. di->anchors = newanchor(++is->nanchors, name, href, target, di->anchors);
  551. if(name != nil)
  552. name = _Strdup(name); // for DestAnchor construction, below
  553. ps->curanchor = is->nanchors;
  554. ps->curfg = push(&ps->fgstk, di->link);
  555. ps->curul = push(&ps->ulstk, ULunder);
  556. }
  557. if(name != nil) {
  558. // add a null item to be destination
  559. additem(ps, newispacer(ISPnull), tok);
  560. di->dests = newdestanchor(++is->nanchors, name, ps->lastit, di->dests);
  561. }
  562. break;
  563. case Ta+RBRA :
  564. if(ps->curanchor != 0) {
  565. ps->curfg = popretnewtop(&ps->fgstk, di->text);
  566. ps->curul = popretnewtop(&ps->ulstk, ULnone);
  567. ps->curanchor = 0;
  568. }
  569. break;
  570. // <!ELEMENT APPLET - - (PARAM | %text)* >
  571. // We can't do applets, so ignore PARAMS, and let
  572. // the %text contents appear for the alternative rep
  573. case Tapplet:
  574. case Tapplet+RBRA:
  575. if(warn && tag == Tapplet)
  576. fprint(2, "warning: <APPLET> ignored\n");
  577. break;
  578. // <!ELEMENT AREA - O EMPTY>
  579. case Tarea:
  580. map = di->maps;
  581. if(map == nil) {
  582. if(warn)
  583. fprint(2, "warning: <AREA> not inside <MAP>\n");
  584. continue;
  585. }
  586. map->areas = newarea(atabval(tok, Ashape, shape_tab, NSHAPETAB, SHrect),
  587. aurlval(tok, Ahref, nil, di->base),
  588. atargval(tok, di->target),
  589. map->areas);
  590. setdimarray(tok, Acoords, &map->areas->coords, &map->areas->ncoords);
  591. break;
  592. // <!ELEMENT (B|STRONG) - - (%text)*>
  593. case Tb:
  594. case Tstrong:
  595. pushfontstyle(ps, FntB);
  596. break;
  597. case Tb+RBRA:
  598. case Tcite+RBRA:
  599. case Tcode+RBRA:
  600. case Tdfn+RBRA:
  601. case Tem+RBRA:
  602. case Tkbd+RBRA:
  603. case Ti+RBRA:
  604. case Tsamp+RBRA:
  605. case Tstrong+RBRA:
  606. case Ttt+RBRA:
  607. case Tvar+RBRA :
  608. case Taddress+RBRA:
  609. popfontstyle(ps);
  610. break;
  611. // <!ELEMENT BASE - O EMPTY>
  612. case Tbase:
  613. t = di->base;
  614. di->base = aurlval(tok, Ahref, di->base, di->base);
  615. if(t != nil)
  616. free(t);
  617. di->target = atargval(tok, di->target);
  618. break;
  619. // <!ELEMENT BASEFONT - O EMPTY>
  620. case Tbasefont:
  621. ps->adjsize = aintval(tok, Asize, 3) - 3;
  622. break;
  623. // <!ELEMENT (BIG|SMALL) - - (%text)*>
  624. case Tbig:
  625. case Tsmall:
  626. sz = ps->adjsize;
  627. if(tag == Tbig)
  628. sz += Large;
  629. else
  630. sz += Small;
  631. pushfontsize(ps, sz);
  632. break;
  633. case Tbig+RBRA:
  634. case Tsmall+RBRA:
  635. popfontsize(ps);
  636. break;
  637. // <!ELEMENT BLOCKQUOTE - - %body.content>
  638. case Tblockquote:
  639. changeindent(ps, BQTAB);
  640. break;
  641. case Tblockquote+RBRA:
  642. changeindent(ps, -BQTAB);
  643. break;
  644. // <!ELEMENT BODY O O %body.content>
  645. case Tbody:
  646. ps->skipping = 0;
  647. bg = makebackground(nil, acolorval(tok, Abgcolor, di->background.color));
  648. bgurl = aurlval(tok, Abackground, nil, di->base);
  649. if(bgurl != nil) {
  650. if(di->backgrounditem != nil)
  651. freeitem((Item*)di->backgrounditem);
  652. // really should remove old item from di->images list,
  653. // but there should only be one BODY element ...
  654. di->backgrounditem = (Iimage*)newiimage(bgurl, nil, ALnone, 0, 0, 0, 0, 0, 0, nil);
  655. di->backgrounditem->nextimage = di->images;
  656. di->images = di->backgrounditem;
  657. }
  658. ps->curbg = bg;
  659. di->background = bg;
  660. di->text = acolorval(tok, Atext, di->text);
  661. di->link = acolorval(tok, Alink, di->link);
  662. di->vlink = acolorval(tok, Avlink, di->vlink);
  663. di->alink = acolorval(tok, Aalink, di->alink);
  664. if(di->text != ps->curfg) {
  665. ps->curfg = di->text;
  666. ps->fgstk.n = 0;
  667. }
  668. break;
  669. case Tbody+RBRA:
  670. // HTML spec says ignore things after </body>,
  671. // but IE and Netscape don't
  672. // ps.skipping = 1;
  673. break;
  674. // <!ELEMENT BR - O EMPTY>
  675. case Tbr:
  676. addlinebrk(ps, atabval(tok, Aclear, clear_tab, NCLEARTAB, 0));
  677. break;
  678. // <!ELEMENT CAPTION - - (%text;)*>
  679. case Tcaption:
  680. if(curtab == nil) {
  681. if(warn)
  682. fprint(2, "warning: <CAPTION> outside <TABLE>\n");
  683. continue;
  684. }
  685. if(curtab->caption != nil) {
  686. if(warn)
  687. fprint(2, "warning: more than one <CAPTION> in <TABLE>\n");
  688. continue;
  689. }
  690. ps = newpstate(ps);
  691. curtab->caption_place = atabval(tok, Aalign, align_tab, NALIGNTAB, ALtop);
  692. break;
  693. case Tcaption+RBRA:
  694. nextps = ps->next;
  695. if(curtab == nil || nextps == nil) {
  696. if(warn)
  697. fprint(2, "warning: unexpected </CAPTION>\n");
  698. continue;
  699. }
  700. curtab->caption = ps->items->next;
  701. free(ps);
  702. ps = nextps;
  703. break;
  704. case Tcenter:
  705. case Tdiv:
  706. if(tag == Tcenter)
  707. al = ALcenter;
  708. else
  709. al = atabval(tok, Aalign, align_tab, NALIGNTAB, ps->curjust);
  710. pushjust(ps, al);
  711. break;
  712. case Tcenter+RBRA:
  713. case Tdiv+RBRA:
  714. popjust(ps);
  715. break;
  716. // <!ELEMENT DD - O %flow >
  717. case Tdd:
  718. if(ps->hangstk.n == 0) {
  719. if(warn)
  720. fprint(2, "warning: <DD> not inside <DL\n");
  721. continue;
  722. }
  723. h = top(&ps->hangstk, 0);
  724. if(h != 0)
  725. changehang(ps, -10*LISTTAB);
  726. else
  727. addbrk(ps, 0, 0);
  728. push(&ps->hangstk, 0);
  729. break;
  730. //<!ELEMENT (DIR|MENU) - - (LI)+ -(%block) >
  731. //<!ELEMENT (OL|UL) - - (LI)+>
  732. case Tdir:
  733. case Tmenu:
  734. case Tol:
  735. case Tul:
  736. changeindent(ps, LISTTAB);
  737. push(&ps->listtypestk, listtyval(tok, (tag==Tol)? LT1 : LTdisc));
  738. push(&ps->listcntstk, aintval(tok, Astart, 1));
  739. break;
  740. case Tdir+RBRA:
  741. case Tmenu+RBRA:
  742. case Tol+RBRA:
  743. case Tul+RBRA:
  744. if(ps->listtypestk.n == 0) {
  745. if(warn)
  746. fprint(2, "warning: %T ended no list\n", tok);
  747. continue;
  748. }
  749. addbrk(ps, 0, 0);
  750. pop(&ps->listtypestk);
  751. pop(&ps->listcntstk);
  752. changeindent(ps, -LISTTAB);
  753. break;
  754. // <!ELEMENT DL - - (DT|DD)+ >
  755. case Tdl:
  756. changeindent(ps, LISTTAB);
  757. push(&ps->hangstk, 0);
  758. break;
  759. case Tdl+RBRA:
  760. if(ps->hangstk.n == 0) {
  761. if(warn)
  762. fprint(2, "warning: unexpected </DL>\n");
  763. continue;
  764. }
  765. changeindent(ps, -LISTTAB);
  766. if(top(&ps->hangstk, 0) != 0)
  767. changehang(ps, -10*LISTTAB);
  768. pop(&ps->hangstk);
  769. break;
  770. // <!ELEMENT DT - O (%text)* >
  771. case Tdt:
  772. if(ps->hangstk.n == 0) {
  773. if(warn)
  774. fprint(2, "warning: <DT> not inside <DL>\n");
  775. continue;
  776. }
  777. h = top(&ps->hangstk, 0);
  778. pop(&ps->hangstk);
  779. if(h != 0)
  780. changehang(ps, -10*LISTTAB);
  781. changehang(ps, 10*LISTTAB);
  782. push(&ps->hangstk, 1);
  783. break;
  784. // <!ELEMENT FONT - - (%text)*>
  785. case Tfont:
  786. sz = top(&ps->fntsizestk, Normal);
  787. if(_tokaval(tok, Asize, &nsz, 0)) {
  788. if(_prefix(L"+", nsz))
  789. sz = Normal + _Strtol(nsz+1, nil, 10) + ps->adjsize;
  790. else if(_prefix(L"-", nsz))
  791. sz = Normal - _Strtol(nsz+1, nil, 10) + ps->adjsize;
  792. else if(nsz != nil)
  793. sz = Normal + (_Strtol(nsz, nil, 10) - 3);
  794. }
  795. ps->curfg = push(&ps->fgstk, acolorval(tok, Acolor, ps->curfg));
  796. pushfontsize(ps, sz);
  797. break;
  798. case Tfont+RBRA:
  799. if(ps->fgstk.n == 0) {
  800. if(warn)
  801. fprint(2, "warning: unexpected </FONT>\n");
  802. continue;
  803. }
  804. ps->curfg = popretnewtop(&ps->fgstk, di->text);
  805. popfontsize(ps);
  806. break;
  807. // <!ELEMENT FORM - - %body.content -(FORM) >
  808. case Tform:
  809. if(is->curform != nil) {
  810. if(warn)
  811. fprint(2, "warning: <FORM> nested inside another\n");
  812. continue;
  813. }
  814. action = aurlval(tok, Aaction, di->base, di->base);
  815. s = aval(tok, Aid);
  816. name = astrval(tok, Aname, s);
  817. if(s)
  818. free(s);
  819. target = atargval(tok, di->target);
  820. method = atabval(tok, Amethod, method_tab, NMETHODTAB, HGet);
  821. if(warn && _tokaval(tok, Aenctype, &enctype, 0) &&
  822. _Strcmp(enctype, L"application/x-www-form-urlencoded"))
  823. fprint(2, "form enctype %S not handled\n", enctype);
  824. frm = newform(++is->nforms, name, action, target, method, di->forms);
  825. di->forms = frm;
  826. is->curform = frm;
  827. break;
  828. case Tform+RBRA:
  829. if(is->curform == nil) {
  830. if(warn)
  831. fprint(2, "warning: unexpected </FORM>\n");
  832. continue;
  833. }
  834. // put fields back in input order
  835. is->curform->fields = (Formfield*)_revlist((List*)is->curform->fields);
  836. is->curform = nil;
  837. break;
  838. // <!ELEMENT FRAME - O EMPTY>
  839. case Tframe:
  840. ks = is->kidstk;
  841. if(ks == nil) {
  842. if(warn)
  843. fprint(2, "warning: <FRAME> not in <FRAMESET>\n");
  844. continue;
  845. }
  846. ks->kidinfos = kd = newkidinfo(0, ks->kidinfos);
  847. kd->src = aurlval(tok, Asrc, nil, di->base);
  848. kd->name = aval(tok, Aname);
  849. if(kd->name == nil)
  850. kd->name = runesmprint("_fr%d", ++is->nframes);
  851. kd->marginw = auintval(tok, Amarginwidth, 0);
  852. kd->marginh = auintval(tok, Amarginheight, 0);
  853. kd->framebd = auintval(tok, Aframeborder, 1);
  854. kd->flags = atabval(tok, Ascrolling, fscroll_tab, NFSCROLLTAB, kd->flags);
  855. norsz = aflagval(tok, Anoresize);
  856. if(norsz)
  857. kd->flags |= FRnoresize;
  858. break;
  859. // <!ELEMENT FRAMESET - - (FRAME|FRAMESET)+>
  860. case Tframeset:
  861. ks = newkidinfo(1, nil);
  862. pks = is->kidstk;
  863. if(pks == nil)
  864. di->kidinfo = ks;
  865. else {
  866. ks->next = pks->kidinfos;
  867. pks->kidinfos = ks;
  868. }
  869. ks->nextframeset = pks;
  870. is->kidstk = ks;
  871. setdimarray(tok, Arows, &ks->rows, &ks->nrows);
  872. if(ks->nrows == 0) {
  873. ks->rows = (Dimen*)emalloc(sizeof(Dimen));
  874. ks->nrows = 1;
  875. ks->rows[0] = makedimen(Dpercent, 100);
  876. }
  877. setdimarray(tok, Acols, &ks->cols, &ks->ncols);
  878. if(ks->ncols == 0) {
  879. ks->cols = (Dimen*)emalloc(sizeof(Dimen));
  880. ks->ncols = 1;
  881. ks->cols[0] = makedimen(Dpercent, 100);
  882. }
  883. break;
  884. case Tframeset+RBRA:
  885. if(is->kidstk == nil) {
  886. if(warn)
  887. fprint(2, "warning: unexpected </FRAMESET>\n");
  888. continue;
  889. }
  890. ks = is->kidstk;
  891. // put kids back in original order
  892. // and add blank frames to fill out cells
  893. n = ks->nrows*ks->ncols;
  894. nblank = n - _listlen((List*)ks->kidinfos);
  895. while(nblank-- > 0)
  896. ks->kidinfos = newkidinfo(0, ks->kidinfos);
  897. ks->kidinfos = (Kidinfo*)_revlist((List*)ks->kidinfos);
  898. is->kidstk = is->kidstk->nextframeset;
  899. if(is->kidstk == nil) {
  900. // end input
  901. ans = nil;
  902. goto return_ans;
  903. }
  904. break;
  905. // <!ELEMENT H1 - - (%text;)*>, etc.
  906. case Th1:
  907. case Th2:
  908. case Th3:
  909. case Th4:
  910. case Th5:
  911. case Th6:
  912. bramt = 1;
  913. if(ps->items == ps->lastit)
  914. bramt = 0;
  915. addbrk(ps, bramt, IFcleft|IFcright);
  916. sz = Verylarge - (tag - Th1);
  917. if(sz < Tiny)
  918. sz = Tiny;
  919. pushfontsize(ps, sz);
  920. sty = top(&ps->fntstylestk, FntR);
  921. if(tag == Th1)
  922. sty = FntB;
  923. pushfontstyle(ps, sty);
  924. pushjust(ps, atabval(tok, Aalign, align_tab, NALIGNTAB, ps->curjust));
  925. ps->skipwhite = 1;
  926. break;
  927. case Th1+RBRA:
  928. case Th2+RBRA:
  929. case Th3+RBRA:
  930. case Th4+RBRA:
  931. case Th5+RBRA:
  932. case Th6+RBRA:
  933. addbrk(ps, 1, IFcleft|IFcright);
  934. popfontsize(ps);
  935. popfontstyle(ps);
  936. popjust(ps);
  937. break;
  938. case Thead:
  939. // HTML spec says ignore regular markup in head,
  940. // but Netscape and IE don't
  941. // ps.skipping = 1;
  942. break;
  943. case Thead+RBRA:
  944. ps->skipping = 0;
  945. break;
  946. // <!ELEMENT HR - O EMPTY>
  947. case Thr:
  948. al = atabval(tok, Aalign, align_tab, NALIGNTAB, ALcenter);
  949. sz = auintval(tok, Asize, HRSZ);
  950. wd = adimen(tok, Awidth);
  951. if(dimenkind(wd) == Dnone)
  952. wd = makedimen(Dpercent, 100);
  953. nosh = aflagval(tok, Anoshade);
  954. color = acolorval(tok, Acolor, 0);
  955. additem(ps, newirule(al, sz, nosh, color, wd), tok);
  956. addbrk(ps, 0, 0);
  957. break;
  958. case Ti:
  959. case Tcite:
  960. case Tdfn:
  961. case Tem:
  962. case Tvar:
  963. case Taddress:
  964. pushfontstyle(ps, FntI);
  965. break;
  966. // <!ELEMENT IMG - O EMPTY>
  967. case Timg:
  968. map = nil;
  969. oldcuranchor = ps->curanchor;
  970. if(_tokaval(tok, Ausemap, &usemap, 0)) {
  971. if(!_prefix(L"#", usemap)) {
  972. if(warn)
  973. fprint(2, "warning: can't handle non-local map %S\n", usemap);
  974. }
  975. else {
  976. map = getmap(di, usemap+1);
  977. if(ps->curanchor == 0) {
  978. di->anchors = newanchor(++is->nanchors, nil, nil, di->target, di->anchors);
  979. ps->curanchor = is->nanchors;
  980. }
  981. }
  982. }
  983. align = atabval(tok, Aalign, align_tab, NALIGNTAB, ALbottom);
  984. dfltbd = 0;
  985. if(ps->curanchor != 0)
  986. dfltbd = 2;
  987. src = aurlval(tok, Asrc, nil, di->base);
  988. if(src == nil) {
  989. if(warn)
  990. fprint(2, "warning: <img> has no src attribute\n");
  991. ps->curanchor = oldcuranchor;
  992. continue;
  993. }
  994. img = newiimage(src,
  995. aval(tok, Aalt),
  996. align,
  997. auintval(tok, Awidth, 0),
  998. auintval(tok, Aheight, 0),
  999. auintval(tok, Ahspace, IMGHSPACE),
  1000. auintval(tok, Avspace, IMGVSPACE),
  1001. auintval(tok, Aborder, dfltbd),
  1002. aflagval(tok, Aismap),
  1003. map);
  1004. if(align == ALleft || align == ALright) {
  1005. additem(ps, newifloat(img, align), tok);
  1006. // if no hspace specified, use FLTIMGHSPACE
  1007. if(!_tokaval(tok, Ahspace, &val, 0))
  1008. ((Iimage*)img)->hspace = FLTIMGHSPACE;
  1009. }
  1010. else {
  1011. ps->skipwhite = 0;
  1012. additem(ps, img, tok);
  1013. }
  1014. if(!ps->skipping) {
  1015. ((Iimage*)img)->nextimage = di->images;
  1016. di->images = (Iimage*)img;
  1017. }
  1018. ps->curanchor = oldcuranchor;
  1019. break;
  1020. // <!ELEMENT INPUT - O EMPTY>
  1021. case Tinput:
  1022. ps->skipwhite = 0;
  1023. if(is->curform == nil) {
  1024. if(warn)
  1025. fprint(2, "<INPUT> not inside <FORM>\n");
  1026. continue;
  1027. }
  1028. is->curform->fields = field = newformfield(
  1029. atabval(tok, Atype, input_tab, NINPUTTAB, Ftext),
  1030. ++is->curform->nfields,
  1031. is->curform,
  1032. aval(tok, Aname),
  1033. aval(tok, Avalue),
  1034. auintval(tok, Asize, 0),
  1035. auintval(tok, Amaxlength, 1000),
  1036. is->curform->fields);
  1037. if(aflagval(tok, Achecked))
  1038. field->flags = FFchecked;
  1039. switch(field->ftype) {
  1040. case Ftext:
  1041. case Fpassword:
  1042. case Ffile:
  1043. if(field->size == 0)
  1044. field->size = 20;
  1045. break;
  1046. case Fcheckbox:
  1047. if(field->name == nil) {
  1048. if(warn)
  1049. fprint(2, "warning: checkbox form field missing name\n");
  1050. continue;
  1051. }
  1052. if(field->value == nil)
  1053. field->value = _Strdup(L"1");
  1054. break;
  1055. case Fradio:
  1056. if(field->name == nil || field->value == nil) {
  1057. if(warn)
  1058. fprint(2, "warning: radio form field missing name or value\n");
  1059. continue;
  1060. }
  1061. break;
  1062. case Fsubmit:
  1063. if(field->value == nil)
  1064. field->value = _Strdup(L"Submit");
  1065. if(field->name == nil)
  1066. field->name = _Strdup(L"_no_name_submit_");
  1067. break;
  1068. case Fimage:
  1069. src = aurlval(tok, Asrc, nil, di->base);
  1070. if(src == nil) {
  1071. if(warn)
  1072. fprint(2, "warning: image form field missing src\n");
  1073. continue;
  1074. }
  1075. // width and height attrs aren't specified in HTML 3.2,
  1076. // but some people provide them and they help avoid
  1077. // a relayout
  1078. field->image = newiimage(src,
  1079. astrval(tok, Aalt, L"Submit"),
  1080. atabval(tok, Aalign, align_tab, NALIGNTAB, ALbottom),
  1081. auintval(tok, Awidth, 0), auintval(tok, Aheight, 0),
  1082. 0, 0, 0, 0, nil);
  1083. ii = (Iimage*)field->image;
  1084. ii->nextimage = di->images;
  1085. di->images = ii;
  1086. break;
  1087. case Freset:
  1088. if(field->value == nil)
  1089. field->value = _Strdup(L"Reset");
  1090. break;
  1091. case Fbutton:
  1092. if(field->value == nil)
  1093. field->value = _Strdup(L" ");
  1094. break;
  1095. }
  1096. ffit = newiformfield(field);
  1097. additem(ps, ffit, tok);
  1098. if(ffit->genattr != nil)
  1099. field->events = ffit->genattr->events;
  1100. break;
  1101. // <!ENTITY ISINDEX - O EMPTY>
  1102. case Tisindex:
  1103. ps->skipwhite = 0;
  1104. prompt = astrval(tok, Aprompt, L"Index search terms:");
  1105. target = atargval(tok, di->target);
  1106. additem(ps, textit(ps, prompt), tok);
  1107. frm = newform(++is->nforms,
  1108. nil,
  1109. di->base,
  1110. target,
  1111. HGet,
  1112. di->forms);
  1113. di->forms = frm;
  1114. ff = newformfield(Ftext,
  1115. 1,
  1116. frm,
  1117. _Strdup(L"_ISINDEX_"),
  1118. nil,
  1119. 50,
  1120. 1000,
  1121. nil);
  1122. frm->fields = ff;
  1123. frm->nfields = 1;
  1124. additem(ps, newiformfield(ff), tok);
  1125. addbrk(ps, 1, 0);
  1126. break;
  1127. // <!ELEMENT LI - O %flow>
  1128. case Tli:
  1129. if(ps->listtypestk.n == 0) {
  1130. if(warn)
  1131. fprint(2, "<LI> not in list\n");
  1132. continue;
  1133. }
  1134. ty = top(&ps->listtypestk, 0);
  1135. ty2 = listtyval(tok, ty);
  1136. if(ty != ty2) {
  1137. ty = ty2;
  1138. push(&ps->listtypestk, ty2);
  1139. }
  1140. v = aintval(tok, Avalue, top(&ps->listcntstk, 1));
  1141. if(ty == LTdisc || ty == LTsquare || ty == LTcircle)
  1142. hang = 10*LISTTAB - 3;
  1143. else
  1144. hang = 10*LISTTAB - 1;
  1145. changehang(ps, hang);
  1146. addtext(ps, listmark(ty, v));
  1147. push(&ps->listcntstk, v + 1);
  1148. changehang(ps, -hang);
  1149. ps->skipwhite = 1;
  1150. break;
  1151. // <!ELEMENT MAP - - (AREA)+>
  1152. case Tmap:
  1153. if(_tokaval(tok, Aname, &name, 0))
  1154. is->curmap = getmap(di, name);
  1155. break;
  1156. case Tmap+RBRA:
  1157. map = is->curmap;
  1158. if(map == nil) {
  1159. if(warn)
  1160. fprint(2, "warning: unexpected </MAP>\n");
  1161. continue;
  1162. }
  1163. map->areas = (Area*)_revlist((List*)map->areas);
  1164. break;
  1165. case Tmeta:
  1166. if(ps->skipping)
  1167. continue;
  1168. if(_tokaval(tok, Ahttp_equiv, &equiv, 0)) {
  1169. val = aval(tok, Acontent);
  1170. n = _Strlen(equiv);
  1171. if(!_Strncmpci(equiv, n, L"refresh"))
  1172. di->refresh = val;
  1173. else if(!_Strncmpci(equiv, n, L"content-script-type")) {
  1174. n = _Strlen(val);
  1175. if(!_Strncmpci(val, n, L"javascript")
  1176. || !_Strncmpci(val, n, L"jscript1.1")
  1177. || !_Strncmpci(val, n, L"jscript"))
  1178. di->scripttype = TextJavascript;
  1179. else {
  1180. if(warn)
  1181. fprint(2, "unimplemented script type %S\n", val);
  1182. di->scripttype = UnknownType;
  1183. }
  1184. }
  1185. }
  1186. break;
  1187. // Nobr is NOT in HMTL 4.0, but it is ubiquitous on the web
  1188. case Tnobr:
  1189. ps->skipwhite = 0;
  1190. ps->curstate &= ~IFwrap;
  1191. break;
  1192. case Tnobr+RBRA:
  1193. ps->curstate |= IFwrap;
  1194. break;
  1195. // We do frames, so skip stuff in noframes
  1196. case Tnoframes:
  1197. ps->skipping = 1;
  1198. break;
  1199. case Tnoframes+RBRA:
  1200. ps->skipping = 0;
  1201. break;
  1202. // We do scripts (if enabled), so skip stuff in noscripts
  1203. case Tnoscript:
  1204. if(doscripts)
  1205. ps->skipping = 1;
  1206. break;
  1207. case Tnoscript+RBRA:
  1208. if(doscripts)
  1209. ps->skipping = 0;
  1210. break;
  1211. // <!ELEMENT OPTION - O ( //PCDATA)>
  1212. case Toption:
  1213. if(is->curform == nil || is->curform->fields == nil) {
  1214. if(warn)
  1215. fprint(2, "warning: <OPTION> not in <SELECT>\n");
  1216. continue;
  1217. }
  1218. field = is->curform->fields;
  1219. if(field->ftype != Fselect) {
  1220. if(warn)
  1221. fprint(2, "warning: <OPTION> not in <SELECT>\n");
  1222. continue;
  1223. }
  1224. val = aval(tok, Avalue);
  1225. option = newoption(aflagval(tok, Aselected), val, nil, field->options);
  1226. field->options = option;
  1227. option->display = getpcdata(toks, tokslen, &toki);
  1228. if(val == nil)
  1229. option->value = _Strdup(option->display);
  1230. break;
  1231. // <!ELEMENT P - O (%text)* >
  1232. case Tp:
  1233. pushjust(ps, atabval(tok, Aalign, align_tab, NALIGNTAB, ps->curjust));
  1234. ps->inpar = 1;
  1235. ps->skipwhite = 1;
  1236. break;
  1237. case Tp+RBRA:
  1238. break;
  1239. // <!ELEMENT PARAM - O EMPTY>
  1240. // Do something when we do applets...
  1241. case Tparam:
  1242. break;
  1243. // <!ELEMENT PRE - - (%text)* -(IMG|BIG|SMALL|SUB|SUP|FONT) >
  1244. case Tpre:
  1245. ps->curstate &= ~IFwrap;
  1246. ps->literal = 1;
  1247. ps->skipwhite = 0;
  1248. pushfontstyle(ps, FntT);
  1249. break;
  1250. case Tpre+RBRA:
  1251. ps->curstate |= IFwrap;
  1252. if(ps->literal) {
  1253. popfontstyle(ps);
  1254. ps->literal = 0;
  1255. }
  1256. break;
  1257. // <!ELEMENT SCRIPT - - CDATA>
  1258. case Tscript:
  1259. if(doscripts) {
  1260. if(!di->hasscripts) {
  1261. if(di->scripttype == TextJavascript) {
  1262. // TODO: initialize script if nec.
  1263. // initjscript(di);
  1264. di->hasscripts = 1;
  1265. }
  1266. }
  1267. }
  1268. if(!di->hasscripts) {
  1269. if(warn)
  1270. fprint(2, "warning: <SCRIPT> ignored\n");
  1271. ps->skipping = 1;
  1272. }
  1273. else {
  1274. scriptsrc = aurlval(tok, Asrc, nil, di->base);
  1275. script = nil;
  1276. if(scriptsrc != nil) {
  1277. if(warn)
  1278. fprint(2, "warning: non-local <SCRIPT> ignored\n");
  1279. free(scriptsrc);
  1280. }
  1281. else {
  1282. script = getpcdata(toks, tokslen, &toki);
  1283. }
  1284. if(script != nil) {
  1285. if(warn)
  1286. fprint(2, "script ignored\n");
  1287. free(script);
  1288. }
  1289. }
  1290. break;
  1291. case Tscript+RBRA:
  1292. ps->skipping = 0;
  1293. break;
  1294. // <!ELEMENT SELECT - - (OPTION+)>
  1295. case Tselect:
  1296. if(is->curform == nil) {
  1297. if(warn)
  1298. fprint(2, "<SELECT> not inside <FORM>\n");
  1299. continue;
  1300. }
  1301. field = newformfield(Fselect,
  1302. ++is->curform->nfields,
  1303. is->curform,
  1304. aval(tok, Aname),
  1305. nil,
  1306. auintval(tok, Asize, 0),
  1307. 0,
  1308. is->curform->fields);
  1309. is->curform->fields = field;
  1310. if(aflagval(tok, Amultiple))
  1311. field->flags = FFmultiple;
  1312. ffit = newiformfield(field);
  1313. additem(ps, ffit, tok);
  1314. if(ffit->genattr != nil)
  1315. field->events = ffit->genattr->events;
  1316. // throw away stuff until next tag (should be <OPTION>)
  1317. s = getpcdata(toks, tokslen, &toki);
  1318. if(s != nil)
  1319. free(s);
  1320. break;
  1321. case Tselect+RBRA:
  1322. if(is->curform == nil || is->curform->fields == nil) {
  1323. if(warn)
  1324. fprint(2, "warning: unexpected </SELECT>\n");
  1325. continue;
  1326. }
  1327. field = is->curform->fields;
  1328. if(field->ftype != Fselect)
  1329. continue;
  1330. // put options back in input order
  1331. field->options = (Option*)_revlist((List*)field->options);
  1332. break;
  1333. // <!ELEMENT (STRIKE|U) - - (%text)*>
  1334. case Tstrike:
  1335. case Tu:
  1336. ps->curul = push(&ps->ulstk, (tag==Tstrike)? ULmid : ULunder);
  1337. break;
  1338. case Tstrike+RBRA:
  1339. case Tu+RBRA:
  1340. if(ps->ulstk.n == 0) {
  1341. if(warn)
  1342. fprint(2, "warning: unexpected %T\n", tok);
  1343. continue;
  1344. }
  1345. ps->curul = popretnewtop(&ps->ulstk, ULnone);
  1346. break;
  1347. // <!ELEMENT STYLE - - CDATA>
  1348. case Tstyle:
  1349. if(warn)
  1350. fprint(2, "warning: unimplemented <STYLE>\n");
  1351. ps->skipping = 1;
  1352. break;
  1353. case Tstyle+RBRA:
  1354. ps->skipping = 0;
  1355. break;
  1356. // <!ELEMENT (SUB|SUP) - - (%text)*>
  1357. case Tsub:
  1358. case Tsup:
  1359. if(tag == Tsub)
  1360. ps->curvoff += SUBOFF;
  1361. else
  1362. ps->curvoff -= SUPOFF;
  1363. push(&ps->voffstk, ps->curvoff);
  1364. sz = top(&ps->fntsizestk, Normal);
  1365. pushfontsize(ps, sz - 1);
  1366. break;
  1367. case Tsub+RBRA:
  1368. case Tsup+RBRA:
  1369. if(ps->voffstk.n == 0) {
  1370. if(warn)
  1371. fprint(2, "warning: unexpected %T\n", tok);
  1372. continue;
  1373. }
  1374. ps->curvoff = popretnewtop(&ps->voffstk, 0);
  1375. popfontsize(ps);
  1376. break;
  1377. // <!ELEMENT TABLE - - (CAPTION?, TR+)>
  1378. case Ttable:
  1379. ps->skipwhite = 0;
  1380. tab = newtable(++is->ntables,
  1381. aalign(tok),
  1382. adimen(tok, Awidth),
  1383. aflagval(tok, Aborder),
  1384. auintval(tok, Acellspacing, TABSP),
  1385. auintval(tok, Acellpadding, TABPAD),
  1386. makebackground(nil, acolorval(tok, Abgcolor, ps->curbg.color)),
  1387. tok,
  1388. is->tabstk);
  1389. is->tabstk = tab;
  1390. curtab = tab;
  1391. break;
  1392. case Ttable+RBRA:
  1393. if(curtab == nil) {
  1394. if(warn)
  1395. fprint(2, "warning: unexpected </TABLE>\n");
  1396. continue;
  1397. }
  1398. isempty = (curtab->cells == nil);
  1399. if(isempty) {
  1400. if(warn)
  1401. fprint(2, "warning: <TABLE> has no cells\n");
  1402. }
  1403. else {
  1404. ps = finishcell(curtab, ps);
  1405. if(curtab->rows != nil)
  1406. curtab->rows->flags = 0;
  1407. finish_table(curtab);
  1408. }
  1409. ps->skipping = 0;
  1410. if(!isempty) {
  1411. tabitem = newitable(curtab);
  1412. al = curtab->align.halign;
  1413. switch(al) {
  1414. case ALleft:
  1415. case ALright:
  1416. additem(ps, newifloat(tabitem, al), tok);
  1417. break;
  1418. default:
  1419. if(al == ALcenter)
  1420. pushjust(ps, ALcenter);
  1421. addbrk(ps, 0, 0);
  1422. if(ps->inpar) {
  1423. popjust(ps);
  1424. ps->inpar = 0;
  1425. }
  1426. additem(ps, tabitem, curtab->tabletok);
  1427. if(al == ALcenter)
  1428. popjust(ps);
  1429. break;
  1430. }
  1431. }
  1432. if(is->tabstk == nil) {
  1433. if(warn)
  1434. fprint(2, "warning: table stack is wrong\n");
  1435. }
  1436. else
  1437. is->tabstk = is->tabstk->next;
  1438. curtab->next = di->tables;
  1439. di->tables = curtab;
  1440. curtab = is->tabstk;
  1441. if(!isempty)
  1442. addbrk(ps, 0, 0);
  1443. break;
  1444. // <!ELEMENT (TH|TD) - O %body.content>
  1445. // Cells for a row are accumulated in reverse order.
  1446. // We push ps on a stack, and use a new one to accumulate
  1447. // the contents of the cell.
  1448. case Ttd:
  1449. case Tth:
  1450. if(curtab == nil) {
  1451. if(warn)
  1452. fprint(2, "%T outside <TABLE>\n", tok);
  1453. continue;
  1454. }
  1455. if(ps->inpar) {
  1456. popjust(ps);
  1457. ps->inpar = 0;
  1458. }
  1459. ps = finishcell(curtab, ps);
  1460. tr = nil;
  1461. if(curtab->rows != nil)
  1462. tr = curtab->rows;
  1463. if(tr == nil || !tr->flags) {
  1464. if(warn)
  1465. fprint(2, "%T outside row\n", tok);
  1466. tr = newtablerow(makealign(ALnone, ALnone),
  1467. makebackground(nil, curtab->background.color),
  1468. TFparsing,
  1469. curtab->rows);
  1470. curtab->rows = tr;
  1471. }
  1472. ps = cell_pstate(ps, tag == Tth);
  1473. flags = TFparsing;
  1474. if(aflagval(tok, Anowrap)) {
  1475. flags |= TFnowrap;
  1476. ps->curstate &= ~IFwrap;
  1477. }
  1478. if(tag == Tth)
  1479. flags |= TFisth;
  1480. c = newtablecell(curtab->cells==nil? 1 : curtab->cells->cellid+1,
  1481. auintval(tok, Arowspan, 1),
  1482. auintval(tok, Acolspan, 1),
  1483. aalign(tok),
  1484. adimen(tok, Awidth),
  1485. auintval(tok, Aheight, 0),
  1486. makebackground(nil, acolorval(tok, Abgcolor, tr->background.color)),
  1487. flags,
  1488. curtab->cells);
  1489. curtab->cells = c;
  1490. ps->curbg = c->background;
  1491. if(c->align.halign == ALnone) {
  1492. if(tr->align.halign != ALnone)
  1493. c->align.halign = tr->align.halign;
  1494. else if(tag == Tth)
  1495. c->align.halign = ALcenter;
  1496. else
  1497. c->align.halign = ALleft;
  1498. }
  1499. if(c->align.valign == ALnone) {
  1500. if(tr->align.valign != ALnone)
  1501. c->align.valign = tr->align.valign;
  1502. else
  1503. c->align.valign = ALmiddle;
  1504. }
  1505. c->nextinrow = tr->cells;
  1506. tr->cells = c;
  1507. break;
  1508. case Ttd+RBRA:
  1509. case Tth+RBRA:
  1510. if(curtab == nil || curtab->cells == nil) {
  1511. if(warn)
  1512. fprint(2, "unexpected %T\n", tok);
  1513. continue;
  1514. }
  1515. ps = finishcell(curtab, ps);
  1516. break;
  1517. // <!ELEMENT TEXTAREA - - ( //PCDATA)>
  1518. case Ttextarea:
  1519. if(is->curform == nil) {
  1520. if(warn)
  1521. fprint(2, "<TEXTAREA> not inside <FORM>\n");
  1522. continue;
  1523. }
  1524. field = newformfield(Ftextarea,
  1525. ++is->curform->nfields,
  1526. is->curform,
  1527. aval(tok, Aname),
  1528. nil,
  1529. 0,
  1530. 0,
  1531. is->curform->fields);
  1532. is->curform->fields = field;
  1533. field->rows = auintval(tok, Arows, 3);
  1534. field->cols = auintval(tok, Acols, 50);
  1535. field->value = getpcdata(toks, tokslen, &toki);
  1536. if(warn && toki < tokslen - 1 && toks[toki + 1].tag != Ttextarea + RBRA)
  1537. fprint(2, "warning: <TEXTAREA> data ended by %T\n", &toks[toki + 1]);
  1538. ffit = newiformfield(field);
  1539. additem(ps, ffit, tok);
  1540. if(ffit->genattr != nil)
  1541. field->events = ffit->genattr->events;
  1542. break;
  1543. // <!ELEMENT TITLE - - ( //PCDATA)* -(%head.misc)>
  1544. case Ttitle:
  1545. di->doctitle = getpcdata(toks, tokslen, &toki);
  1546. if(warn && toki < tokslen - 1 && toks[toki + 1].tag != Ttitle + RBRA)
  1547. fprint(2, "warning: <TITLE> data ended by %T\n", &toks[toki + 1]);
  1548. break;
  1549. // <!ELEMENT TR - O (TH|TD)+>
  1550. // rows are accumulated in reverse order in curtab->rows
  1551. case Ttr:
  1552. if(curtab == nil) {
  1553. if(warn)
  1554. fprint(2, "warning: <TR> outside <TABLE>\n");
  1555. continue;
  1556. }
  1557. if(ps->inpar) {
  1558. popjust(ps);
  1559. ps->inpar = 0;
  1560. }
  1561. ps = finishcell(curtab, ps);
  1562. if(curtab->rows != nil)
  1563. curtab->rows->flags = 0;
  1564. curtab->rows = newtablerow(aalign(tok),
  1565. makebackground(nil, acolorval(tok, Abgcolor, curtab->background.color)),
  1566. TFparsing,
  1567. curtab->rows);
  1568. break;
  1569. case Ttr+RBRA:
  1570. if(curtab == nil || curtab->rows == nil) {
  1571. if(warn)
  1572. fprint(2, "warning: unexpected </TR>\n");
  1573. continue;
  1574. }
  1575. ps = finishcell(curtab, ps);
  1576. tr = curtab->rows;
  1577. if(tr->cells == nil) {
  1578. if(warn)
  1579. fprint(2, "warning: empty row\n");
  1580. curtab->rows = tr->next;
  1581. tr->next = nil;
  1582. }
  1583. else
  1584. tr->flags = 0;
  1585. break;
  1586. // <!ELEMENT (TT|CODE|KBD|SAMP) - - (%text)*>
  1587. case Ttt:
  1588. case Tcode:
  1589. case Tkbd:
  1590. case Tsamp:
  1591. pushfontstyle(ps, FntT);
  1592. break;
  1593. // Tags that have empty action
  1594. case Tabbr:
  1595. case Tabbr+RBRA:
  1596. case Tacronym:
  1597. case Tacronym+RBRA:
  1598. case Tarea+RBRA:
  1599. case Tbase+RBRA:
  1600. case Tbasefont+RBRA:
  1601. case Tbr+RBRA:
  1602. case Tdd+RBRA:
  1603. case Tdt+RBRA:
  1604. case Tframe+RBRA:
  1605. case Thr+RBRA:
  1606. case Thtml:
  1607. case Thtml+RBRA:
  1608. case Timg+RBRA:
  1609. case Tinput+RBRA:
  1610. case Tisindex+RBRA:
  1611. case Tli+RBRA:
  1612. case Tlink:
  1613. case Tlink+RBRA:
  1614. case Tmeta+RBRA:
  1615. case Toption+RBRA:
  1616. case Tparam+RBRA:
  1617. case Ttextarea+RBRA:
  1618. case Ttitle+RBRA:
  1619. break;
  1620. // Tags not implemented
  1621. case Tbdo:
  1622. case Tbdo+RBRA:
  1623. case Tbutton:
  1624. case Tbutton+RBRA:
  1625. case Tdel:
  1626. case Tdel+RBRA:
  1627. case Tfieldset:
  1628. case Tfieldset+RBRA:
  1629. case Tiframe:
  1630. case Tiframe+RBRA:
  1631. case Tins:
  1632. case Tins+RBRA:
  1633. case Tlabel:
  1634. case Tlabel+RBRA:
  1635. case Tlegend:
  1636. case Tlegend+RBRA:
  1637. case Tobject:
  1638. case Tobject+RBRA:
  1639. case Toptgroup:
  1640. case Toptgroup+RBRA:
  1641. case Tspan:
  1642. case Tspan+RBRA:
  1643. if(warn) {
  1644. if(tag > RBRA)
  1645. tag -= RBRA;
  1646. fprint(2, "warning: unimplemented HTML tag: %S\n", tagnames[tag]);
  1647. }
  1648. break;
  1649. default:
  1650. if(warn)
  1651. fprint(2, "warning: unknown HTML tag: %S\n", tok->text);
  1652. break;
  1653. }
  1654. }
  1655. // some pages omit trailing </table>
  1656. while(curtab != nil) {
  1657. if(warn)
  1658. fprint(2, "warning: <TABLE> not closed\n");
  1659. if(curtab->cells != nil) {
  1660. ps = finishcell(curtab, ps);
  1661. if(curtab->cells == nil) {
  1662. if(warn)
  1663. fprint(2, "warning: empty table\n");
  1664. }
  1665. else {
  1666. if(curtab->rows != nil)
  1667. curtab->rows->flags = 0;
  1668. finish_table(curtab);
  1669. ps->skipping = 0;
  1670. additem(ps, newitable(curtab), curtab->tabletok);
  1671. addbrk(ps, 0, 0);
  1672. }
  1673. }
  1674. if(is->tabstk != nil)
  1675. is->tabstk = is->tabstk->next;
  1676. curtab->next = di->tables;
  1677. di->tables = curtab;
  1678. curtab = is->tabstk;
  1679. }
  1680. outerps = lastps(ps);
  1681. ans = outerps->items->next;
  1682. freeitem(outerps->items);
  1683. // note: ans may be nil and di->kids not nil, if there's a frameset!
  1684. outerps->items = newispacer(ISPnull);
  1685. outerps->lastit = outerps->items;
  1686. is->psstk = ps;
  1687. if(ans != nil && di->hasscripts) {
  1688. // TODO evalscript(nil);
  1689. ;
  1690. }
  1691. return_ans:
  1692. if(dbgbuild) {
  1693. assert(validitems(ans));
  1694. if(ans == nil)
  1695. fprint(2, "getitems returning nil\n");
  1696. else
  1697. printitems(ans, "getitems returning:");
  1698. }
  1699. return ans;
  1700. }
  1701. // Concatenate together maximal set of Data tokens, starting at toks[toki+1].
  1702. // Lexer has ensured that there will either be a following non-data token or
  1703. // we will be at eof.
  1704. // Return emallocd trimmed concatenation, and update *ptoki to last used toki
  1705. static Rune*
  1706. getpcdata(Token* toks, int tokslen, int* ptoki)
  1707. {
  1708. Rune* ans;
  1709. Rune* p;
  1710. Rune* trimans;
  1711. int anslen;
  1712. int trimanslen;
  1713. int toki;
  1714. Token* tok;
  1715. ans = nil;
  1716. anslen = 0;
  1717. // first find length of answer
  1718. toki = (*ptoki) + 1;
  1719. while(toki < tokslen) {
  1720. tok = &toks[toki];
  1721. if(tok->tag == Data) {
  1722. toki++;
  1723. anslen += _Strlen(tok->text);
  1724. }
  1725. else
  1726. break;
  1727. }
  1728. // now make up the initial answer
  1729. if(anslen > 0) {
  1730. ans = _newstr(anslen);
  1731. p = ans;
  1732. toki = (*ptoki) + 1;
  1733. while(toki < tokslen) {
  1734. tok = &toks[toki];
  1735. if(tok->tag == Data) {
  1736. toki++;
  1737. p = _Stradd(p, tok->text, _Strlen(tok->text));
  1738. }
  1739. else
  1740. break;
  1741. }
  1742. *p = 0;
  1743. _trimwhite(ans, anslen, &trimans, &trimanslen);
  1744. if(trimanslen != anslen) {
  1745. p = ans;
  1746. ans = _Strndup(trimans, trimanslen);
  1747. free(p);
  1748. }
  1749. }
  1750. *ptoki = toki-1;
  1751. return ans;
  1752. }
  1753. // If still parsing head of curtab->cells list, finish it off
  1754. // by transferring the items on the head of psstk to the cell.
  1755. // Then pop the psstk and return the new psstk.
  1756. static Pstate*
  1757. finishcell(Table* curtab, Pstate* psstk)
  1758. {
  1759. Tablecell* c;
  1760. Pstate* psstknext;
  1761. c = curtab->cells;
  1762. if(c != nil) {
  1763. if((c->flags&TFparsing)) {
  1764. psstknext = psstk->next;
  1765. if(psstknext == nil) {
  1766. if(warn)
  1767. fprint(2, "warning: parse state stack is wrong\n");
  1768. }
  1769. else {
  1770. c->content = psstk->items->next;
  1771. c->flags &= ~TFparsing;
  1772. freepstate(psstk);
  1773. psstk = psstknext;
  1774. }
  1775. }
  1776. }
  1777. return psstk;
  1778. }
  1779. // Make a new Pstate for a cell, based on the old pstate, oldps.
  1780. // Also, put the new ps on the head of the oldps stack.
  1781. static Pstate*
  1782. cell_pstate(Pstate* oldps, int ishead)
  1783. {
  1784. Pstate* ps;
  1785. int sty;
  1786. ps = newpstate(oldps);
  1787. ps->skipwhite = 1;
  1788. ps->curanchor = oldps->curanchor;
  1789. copystack(&ps->fntstylestk, &oldps->fntstylestk);
  1790. copystack(&ps->fntsizestk, &oldps->fntsizestk);
  1791. ps->curfont = oldps->curfont;
  1792. ps->curfg = oldps->curfg;
  1793. ps->curbg = oldps->curbg;
  1794. copystack(&ps->fgstk, &oldps->fgstk);
  1795. ps->adjsize = oldps->adjsize;
  1796. if(ishead) {
  1797. sty = ps->curfont%NumSize;
  1798. ps->curfont = FntB*NumSize + sty;
  1799. }
  1800. return ps;
  1801. }
  1802. // Return a new Pstate with default starting state.
  1803. // Use link to add it to head of a list, if any.
  1804. static Pstate*
  1805. newpstate(Pstate* link)
  1806. {
  1807. Pstate* ps;
  1808. ps = (Pstate*)emalloc(sizeof(Pstate));
  1809. ps->curfont = DefFnt;
  1810. ps->curfg = Black;
  1811. ps->curbg.image = nil;
  1812. ps->curbg.color = White;
  1813. ps->curul = ULnone;
  1814. ps->curjust = ALleft;
  1815. ps->curstate = IFwrap;
  1816. ps->items = newispacer(ISPnull);
  1817. ps->lastit = ps->items;
  1818. ps->prelastit = nil;
  1819. ps->next = link;
  1820. return ps;
  1821. }
  1822. // Return last Pstate on psl list
  1823. static Pstate*
  1824. lastps(Pstate* psl)
  1825. {
  1826. assert(psl != nil);
  1827. while(psl->next != nil)
  1828. psl = psl->next;
  1829. return psl;
  1830. }
  1831. // Add it to end of ps item chain, adding in current state from ps.
  1832. // Also, if tok is not nil, scan it for generic attributes and assign
  1833. // the genattr field of the item accordingly.
  1834. static void
  1835. additem(Pstate* ps, Item* it, Token* tok)
  1836. {
  1837. int aid;
  1838. int any;
  1839. Rune* i;
  1840. Rune* c;
  1841. Rune* s;
  1842. Rune* t;
  1843. Attr* a;
  1844. SEvent* e;
  1845. if(ps->skipping) {
  1846. if(warn)
  1847. fprint(2, "warning: skipping item: %I\n", it);
  1848. return;
  1849. }
  1850. it->anchorid = ps->curanchor;
  1851. it->state |= ps->curstate;
  1852. if(tok != nil) {
  1853. any = 0;
  1854. i = nil;
  1855. c = nil;
  1856. s = nil;
  1857. t = nil;
  1858. e = nil;
  1859. for(a = tok->attr; a != nil; a = a->next) {
  1860. aid = a->attid;
  1861. if(!attrinfo[aid])
  1862. continue;
  1863. switch(aid) {
  1864. case Aid:
  1865. i = a->value;
  1866. break;
  1867. case Aclass:
  1868. c = a->value;
  1869. break;
  1870. case Astyle:
  1871. s = a->value;
  1872. break;
  1873. case Atitle:
  1874. t = a->value;
  1875. break;
  1876. default:
  1877. assert(aid >= Aonblur && aid <= Aonunload);
  1878. e = newscriptevent(scriptev[a->attid], a->value, e);
  1879. break;
  1880. }
  1881. a->value = nil;
  1882. any = 1;
  1883. }
  1884. if(any)
  1885. it->genattr = newgenattr(i, c, s, t, e);
  1886. }
  1887. ps->curstate &= ~(IFbrk|IFbrksp|IFnobrk|IFcleft|IFcright);
  1888. ps->prelastit = ps->lastit;
  1889. ps->lastit->next = it;
  1890. ps->lastit = it;
  1891. }
  1892. // Make a text item out of s,
  1893. // using current font, foreground, vertical offset and underline state.
  1894. static Item*
  1895. textit(Pstate* ps, Rune* s)
  1896. {
  1897. assert(s != nil);
  1898. return newitext(s, ps->curfont, ps->curfg, ps->curvoff + Voffbias, ps->curul);
  1899. }
  1900. // Add text item or items for s, paying attention to
  1901. // current font, foreground, baseline offset, underline state,
  1902. // and literal mode. Unless we're in literal mode, compress
  1903. // whitespace to single blank, and, if curstate has a break,
  1904. // trim any leading whitespace. Whether in literal mode or not,
  1905. // turn nonbreaking spaces into spacer items with IFnobrk set.
  1906. //
  1907. // In literal mode, break up s at newlines and add breaks instead.
  1908. // Also replace tabs appropriate number of spaces.
  1909. // In nonliteral mode, break up the items every 100 or so characters
  1910. // just to make the layout algorithm not go quadratic.
  1911. //
  1912. // addtext assumes ownership of s.
  1913. static void
  1914. addtext(Pstate* ps, Rune* s)
  1915. {
  1916. int n;
  1917. int i;
  1918. int j;
  1919. int k;
  1920. int col;
  1921. int c;
  1922. int nsp;
  1923. Item* it;
  1924. Rune* ss;
  1925. Rune* p;
  1926. Rune buf[SMALLBUFSIZE];
  1927. assert(s != nil);
  1928. n = runestrlen(s);
  1929. i = 0;
  1930. j = 0;
  1931. if(ps->literal) {
  1932. col = 0;
  1933. while(i < n) {
  1934. if(s[i] == '\n') {
  1935. if(i > j) {
  1936. // trim trailing blanks from line
  1937. for(k = i; k > j; k--)
  1938. if(s[k - 1] != ' ')
  1939. break;
  1940. if(k > j)
  1941. additem(ps, textit(ps, _Strndup(s+j, k-j)), nil);
  1942. }
  1943. addlinebrk(ps, 0);
  1944. j = i + 1;
  1945. col = 0;
  1946. }
  1947. else {
  1948. if(s[i] == '\t') {
  1949. col += i - j;
  1950. nsp = 8 - (col%8);
  1951. // make ss = s[j:i] + nsp spaces
  1952. ss = _newstr(i-j+nsp);
  1953. p = _Stradd(ss, s+j, i-j);
  1954. p = _Stradd(p, L" ", nsp);
  1955. *p = 0;
  1956. additem(ps, textit(ps, ss), nil);
  1957. col += nsp;
  1958. j = i + 1;
  1959. }
  1960. else if(s[i] == NBSP) {
  1961. if(i > j)
  1962. additem(ps, textit(ps, _Strndup(s+j, i-j)), nil);
  1963. addnbsp(ps);
  1964. col += (i - j) + 1;
  1965. j = i + 1;
  1966. }
  1967. }
  1968. i++;
  1969. }
  1970. if(i > j) {
  1971. if(j == 0 && i == n) {
  1972. // just transfer s over
  1973. additem(ps, textit(ps, s), nil);
  1974. }
  1975. else {
  1976. additem(ps, textit(ps, _Strndup(s+j, i-j)), nil);
  1977. free(s);
  1978. }
  1979. }
  1980. }
  1981. else { // not literal mode
  1982. if((ps->curstate&IFbrk) || ps->lastit == ps->items)
  1983. while(i < n) {
  1984. c = s[i];
  1985. if(c >= 256 || !isspace(c))
  1986. break;
  1987. i++;
  1988. }
  1989. p = buf;
  1990. for(j = i; i < n; i++) {
  1991. assert(p+i-j < buf+SMALLBUFSIZE-1);
  1992. c = s[i];
  1993. if(c == NBSP) {
  1994. if(i > j)
  1995. p = _Stradd(p, s+j, i-j);
  1996. if(p > buf)
  1997. additem(ps, textit(ps, _Strndup(buf, p-buf)), nil);
  1998. p = buf;
  1999. addnbsp(ps);
  2000. j = i + 1;
  2001. continue;
  2002. }
  2003. if(c < 256 && isspace(c)) {
  2004. if(i > j)
  2005. p = _Stradd(p, s+j, i-j);
  2006. *p++ = ' ';
  2007. while(i < n - 1) {
  2008. c = s[i + 1];
  2009. if(c >= 256 || !isspace(c))
  2010. break;
  2011. i++;
  2012. }
  2013. j = i + 1;
  2014. }
  2015. if(i - j >= 100) {
  2016. p = _Stradd(p, s+j, i+1-j);
  2017. j = i + 1;
  2018. }
  2019. if(p-buf >= 100) {
  2020. additem(ps, textit(ps, _Strndup(buf, p-buf)), nil);
  2021. p = buf;
  2022. }
  2023. }
  2024. if(i > j && j < n) {
  2025. assert(p+i-j < buf+SMALLBUFSIZE-1);
  2026. p = _Stradd(p, s+j, i-j);
  2027. }
  2028. // don't add a space if previous item ended in a space
  2029. if(p-buf == 1 && buf[0] == ' ' && ps->lastit != nil) {
  2030. it = ps->lastit;
  2031. if(it->tag == Itexttag) {
  2032. ss = ((Itext*)it)->s;
  2033. k = _Strlen(ss);
  2034. if(k > 0 && ss[k] == ' ')
  2035. p = buf;
  2036. }
  2037. }
  2038. if(p > buf)
  2039. additem(ps, textit(ps, _Strndup(buf, p-buf)), nil);
  2040. free(s);
  2041. }
  2042. }
  2043. // Add a break to ps->curstate, with extra space if sp is true.
  2044. // If there was a previous break, combine this one's parameters
  2045. // with that to make the amt be the max of the two and the clr
  2046. // be the most general. (amt will be 0 or 1)
  2047. // Also, if the immediately preceding item was a text item,
  2048. // trim any whitespace from the end of it, if not in literal mode.
  2049. // Finally, if this is at the very beginning of the item list
  2050. // (the only thing there is a null spacer), then don't add the space.
  2051. static void
  2052. addbrk(Pstate* ps, int sp, int clr)
  2053. {
  2054. int state;
  2055. Rune* l;
  2056. int nl;
  2057. Rune* r;
  2058. int nr;
  2059. Itext* t;
  2060. Rune* s;
  2061. state = ps->curstate;
  2062. clr = clr|(state&(IFcleft|IFcright));
  2063. if(sp && !(ps->lastit == ps->items))
  2064. sp = IFbrksp;
  2065. else
  2066. sp = 0;
  2067. ps->curstate = IFbrk|sp|(state&~(IFcleft|IFcright))|clr;
  2068. if(ps->lastit != ps->items) {
  2069. if(!ps->literal && ps->lastit->tag == Itexttag) {
  2070. t = (Itext*)ps->lastit;
  2071. _splitr(t->s, _Strlen(t->s), notwhitespace, &l, &nl, &r, &nr);
  2072. // try to avoid making empty items
  2073. // but not crucial f the occasional one gets through
  2074. if(nl == 0 && ps->prelastit != nil) {
  2075. ps->lastit = ps->prelastit;
  2076. ps->lastit->next = nil;
  2077. ps->prelastit = nil;
  2078. }
  2079. else {
  2080. s = t->s;
  2081. if(nl == 0) {
  2082. // need a non-nil pointer to empty string
  2083. // (_Strdup(L"") returns nil)
  2084. t->s = emalloc(sizeof(Rune));
  2085. t->s[0] = 0;
  2086. }
  2087. else
  2088. t->s = _Strndup(l, nl);
  2089. if(s)
  2090. free(s);
  2091. }
  2092. }
  2093. }
  2094. }
  2095. // Add break due to a <br> or a newline within a preformatted section.
  2096. // We add a null item first, with current font's height and ascent, to make
  2097. // sure that the current line takes up at least that amount of vertical space.
  2098. // This ensures that <br>s on empty lines cause blank lines, and that
  2099. // multiple <br>s in a row give multiple blank lines.
  2100. // However don't add the spacer if the previous item was something that
  2101. // takes up space itself.
  2102. static void
  2103. addlinebrk(Pstate* ps, int clr)
  2104. {
  2105. int obrkstate;
  2106. int b;
  2107. // don't want break before our null item unless the previous item
  2108. // was also a null item for the purposes of line breaking
  2109. obrkstate = ps->curstate&(IFbrk|IFbrksp);
  2110. b = IFnobrk;
  2111. if(ps->lastit != nil) {
  2112. if(ps->lastit->tag == Ispacertag) {
  2113. if(((Ispacer*)ps->lastit)->spkind == ISPvline)
  2114. b = IFbrk;
  2115. }
  2116. }
  2117. ps->curstate = (ps->curstate&~(IFbrk|IFbrksp))|b;
  2118. additem(ps, newispacer(ISPvline), nil);
  2119. ps->curstate = (ps->curstate&~(IFbrk|IFbrksp))|obrkstate;
  2120. addbrk(ps, 0, clr);
  2121. }
  2122. // Add a nonbreakable space
  2123. static void
  2124. addnbsp(Pstate* ps)
  2125. {
  2126. // if nbsp comes right where a break was specified,
  2127. // do the break anyway (nbsp is being used to generate undiscardable
  2128. // space rather than to prevent a break)
  2129. if((ps->curstate&IFbrk) == 0)
  2130. ps->curstate |= IFnobrk;
  2131. additem(ps, newispacer(ISPhspace), nil);
  2132. // but definitely no break on next item
  2133. ps->curstate |= IFnobrk;
  2134. }
  2135. // Change hang in ps.curstate by delta.
  2136. // The amount is in 1/10ths of tabs, and is the amount that
  2137. // the current contiguous set of items with a hang value set
  2138. // is to be shifted left from its normal (indented) place.
  2139. static void
  2140. changehang(Pstate* ps, int delta)
  2141. {
  2142. int amt;
  2143. amt = (ps->curstate&IFhangmask) + delta;
  2144. if(amt < 0) {
  2145. if(warn)
  2146. fprint(2, "warning: hang went negative\n");
  2147. amt = 0;
  2148. }
  2149. ps->curstate = (ps->curstate&~IFhangmask)|amt;
  2150. }
  2151. // Change indent in ps.curstate by delta.
  2152. static void
  2153. changeindent(Pstate* ps, int delta)
  2154. {
  2155. int amt;
  2156. amt = ((ps->curstate&IFindentmask) >> IFindentshift) + delta;
  2157. if(amt < 0) {
  2158. if(warn)
  2159. fprint(2, "warning: indent went negative\n");
  2160. amt = 0;
  2161. }
  2162. ps->curstate = (ps->curstate&~IFindentmask)|(amt << IFindentshift);
  2163. }
  2164. // Push val on top of stack, and also return value pushed
  2165. static int
  2166. push(Stack* stk, int val)
  2167. {
  2168. if(stk->n == Nestmax) {
  2169. if(warn)
  2170. fprint(2, "warning: build stack overflow\n");
  2171. }
  2172. else
  2173. stk->slots[stk->n++] = val;
  2174. return val;
  2175. }
  2176. // Pop top of stack
  2177. static void
  2178. pop(Stack* stk)
  2179. {
  2180. if(stk->n > 0)
  2181. --stk->n;
  2182. }
  2183. //Return top of stack, using dflt if stack is empty
  2184. static int
  2185. top(Stack* stk, int dflt)
  2186. {
  2187. if(stk->n == 0)
  2188. return dflt;
  2189. return stk->slots[stk->n-1];
  2190. }
  2191. // pop, then return new top, with dflt if empty
  2192. static int
  2193. popretnewtop(Stack* stk, int dflt)
  2194. {
  2195. if(stk->n == 0)
  2196. return dflt;
  2197. stk->n--;
  2198. if(stk->n == 0)
  2199. return dflt;
  2200. return stk->slots[stk->n-1];
  2201. }
  2202. // Copy fromstk entries into tostk
  2203. static void
  2204. copystack(Stack* tostk, Stack* fromstk)
  2205. {
  2206. int n;
  2207. n = fromstk->n;
  2208. tostk->n = n;
  2209. memmove(tostk->slots, fromstk->slots, n*sizeof(int));
  2210. }
  2211. static void
  2212. popfontstyle(Pstate* ps)
  2213. {
  2214. pop(&ps->fntstylestk);
  2215. setcurfont(ps);
  2216. }
  2217. static void
  2218. pushfontstyle(Pstate* ps, int sty)
  2219. {
  2220. push(&ps->fntstylestk, sty);
  2221. setcurfont(ps);
  2222. }
  2223. static void
  2224. popfontsize(Pstate* ps)
  2225. {
  2226. pop(&ps->fntsizestk);
  2227. setcurfont(ps);
  2228. }
  2229. static void
  2230. pushfontsize(Pstate* ps, int sz)
  2231. {
  2232. push(&ps->fntsizestk, sz);
  2233. setcurfont(ps);
  2234. }
  2235. static void
  2236. setcurfont(Pstate* ps)
  2237. {
  2238. int sty;
  2239. int sz;
  2240. sty = top(&ps->fntstylestk, FntR);
  2241. sz = top(&ps->fntsizestk, Normal);
  2242. if(sz < Tiny)
  2243. sz = Tiny;
  2244. if(sz > Verylarge)
  2245. sz = Verylarge;
  2246. ps->curfont = sty*NumSize + sz;
  2247. }
  2248. static void
  2249. popjust(Pstate* ps)
  2250. {
  2251. pop(&ps->juststk);
  2252. setcurjust(ps);
  2253. }
  2254. static void
  2255. pushjust(Pstate* ps, int j)
  2256. {
  2257. push(&ps->juststk, j);
  2258. setcurjust(ps);
  2259. }
  2260. static void
  2261. setcurjust(Pstate* ps)
  2262. {
  2263. int j;
  2264. int state;
  2265. j = top(&ps->juststk, ALleft);
  2266. if(j != ps->curjust) {
  2267. ps->curjust = j;
  2268. state = ps->curstate;
  2269. state &= ~(IFrjust|IFcjust);
  2270. if(j == ALcenter)
  2271. state |= IFcjust;
  2272. else if(j == ALright)
  2273. state |= IFrjust;
  2274. ps->curstate = state;
  2275. }
  2276. }
  2277. // Do final rearrangement after table parsing is finished
  2278. // and assign cells to grid points
  2279. static void
  2280. finish_table(Table* t)
  2281. {
  2282. int ncol;
  2283. int nrow;
  2284. int r;
  2285. Tablerow* rl;
  2286. Tablecell* cl;
  2287. int* rowspancnt;
  2288. Tablecell** rowspancell;
  2289. int ri;
  2290. int ci;
  2291. Tablecell* c;
  2292. Tablecell* cnext;
  2293. Tablerow* row;
  2294. Tablerow* rownext;
  2295. int rcols;
  2296. int newncol;
  2297. int k;
  2298. int j;
  2299. int cspan;
  2300. int rspan;
  2301. int i;
  2302. rl = t->rows;
  2303. t->nrow = nrow = _listlen((List*)rl);
  2304. t->rows = (Tablerow*)emalloc(nrow * sizeof(Tablerow));
  2305. ncol = 0;
  2306. r = nrow - 1;
  2307. for(row = rl; row != nil; row = rownext) {
  2308. // copy the data from the allocated Tablerow into the array slot
  2309. t->rows[r] = *row;
  2310. rownext = row->next;
  2311. row = &t->rows[r];
  2312. r--;
  2313. rcols = 0;
  2314. c = row->cells;
  2315. // If rowspan is > 1 but this is the last row,
  2316. // reset the rowspan
  2317. if(c != nil && c->rowspan > 1 && r == nrow-2)
  2318. c->rowspan = 1;
  2319. // reverse row->cells list (along nextinrow pointers)
  2320. row->cells = nil;
  2321. while(c != nil) {
  2322. cnext = c->nextinrow;
  2323. c->nextinrow = row->cells;
  2324. row->cells = c;
  2325. rcols += c->colspan;
  2326. c = cnext;
  2327. }
  2328. if(rcols > ncol)
  2329. ncol = rcols;
  2330. }
  2331. t->ncol = ncol;
  2332. t->cols = (Tablecol*)emalloc(ncol * sizeof(Tablecol));
  2333. // Reverse cells just so they are drawn in source order.
  2334. // Also, trim their contents so they don't end in whitespace.
  2335. t->cells = (Tablecell*)_revlist((List*)t->cells);
  2336. for(c = t->cells; c != nil; c= c->next)
  2337. trim_cell(c);
  2338. t->grid = (Tablecell***)emalloc(nrow * sizeof(Tablecell**));
  2339. for(i = 0; i < nrow; i++)
  2340. t->grid[i] = (Tablecell**)emalloc(ncol * sizeof(Tablecell*));
  2341. // The following arrays keep track of cells that are spanning
  2342. // multiple rows; rowspancnt[i] is the number of rows left
  2343. // to be spanned in column i.
  2344. // When done, cell's (row,col) is upper left grid point.
  2345. rowspancnt = (int*)emalloc(ncol * sizeof(int));
  2346. rowspancell = (Tablecell**)emalloc(ncol * sizeof(Tablecell*));
  2347. for(ri = 0; ri < nrow; ri++) {
  2348. row = &t->rows[ri];
  2349. cl = row->cells;
  2350. ci = 0;
  2351. while(ci < ncol || cl != nil) {
  2352. if(ci < ncol && rowspancnt[ci] > 0) {
  2353. t->grid[ri][ci] = rowspancell[ci];
  2354. rowspancnt[ci]--;
  2355. ci++;
  2356. }
  2357. else {
  2358. if(cl == nil) {
  2359. ci++;
  2360. continue;
  2361. }
  2362. c = cl;
  2363. cl = cl->nextinrow;
  2364. cspan = c->colspan;
  2365. rspan = c->rowspan;
  2366. if(ci + cspan > ncol) {
  2367. // because of row spanning, we calculated
  2368. // ncol incorrectly; adjust it
  2369. newncol = ci + cspan;
  2370. t->cols = (Tablecol*)erealloc(t->cols, newncol * sizeof(Tablecol));
  2371. rowspancnt = (int*)erealloc(rowspancnt, newncol * sizeof(int));
  2372. rowspancell = (Tablecell**)erealloc(rowspancell, newncol * sizeof(Tablecell*));
  2373. k = newncol-ncol;
  2374. memset(t->cols+ncol, 0, k*sizeof(Tablecol));
  2375. memset(rowspancnt+ncol, 0, k*sizeof(int));
  2376. memset(rowspancell+ncol, 0, k*sizeof(Tablecell*));
  2377. for(j = 0; j < nrow; j++) {
  2378. t->grid[j] = (Tablecell**)erealloc(t->grid[j], newncol * sizeof(Tablecell*));
  2379. memset(t->grid[j], 0, k*sizeof(Tablecell*));
  2380. }
  2381. t->ncol = ncol = newncol;
  2382. }
  2383. c->row = ri;
  2384. c->col = ci;
  2385. for(i = 0; i < cspan; i++) {
  2386. t->grid[ri][ci] = c;
  2387. if(rspan > 1) {
  2388. rowspancnt[ci] = rspan - 1;
  2389. rowspancell[ci] = c;
  2390. }
  2391. ci++;
  2392. }
  2393. }
  2394. }
  2395. }
  2396. free(rowspancnt);
  2397. free(rowspancell);
  2398. }
  2399. // Remove tail of cell content until it isn't whitespace.
  2400. static void
  2401. trim_cell(Tablecell* c)
  2402. {
  2403. int dropping;
  2404. Rune* s;
  2405. Rune* x;
  2406. Rune* y;
  2407. int nx;
  2408. int ny;
  2409. Item* p;
  2410. Itext* q;
  2411. Item* pprev;
  2412. dropping = 1;
  2413. while(c->content != nil && dropping) {
  2414. p = c->content;
  2415. pprev = nil;
  2416. while(p->next != nil) {
  2417. pprev = p;
  2418. p = p->next;
  2419. }
  2420. dropping = 0;
  2421. if(!(p->state&IFnobrk)) {
  2422. if(p->tag == Itexttag) {
  2423. q = (Itext*)p;
  2424. s = q->s;
  2425. _splitr(s, _Strlen(s), notwhitespace, &x, &nx, &y, &ny);
  2426. if(nx != 0 && ny != 0) {
  2427. q->s = _Strndup(x, nx);
  2428. free(s);
  2429. }
  2430. break;
  2431. }
  2432. }
  2433. if(dropping) {
  2434. if(pprev == nil)
  2435. c->content = nil;
  2436. else
  2437. pprev->next = nil;
  2438. freeitem(p);
  2439. }
  2440. }
  2441. }
  2442. // Caller must free answer (eventually).
  2443. static Rune*
  2444. listmark(uchar ty, int n)
  2445. {
  2446. Rune* s;
  2447. Rune* t;
  2448. int n2;
  2449. int i;
  2450. s = nil;
  2451. switch(ty) {
  2452. case LTdisc:
  2453. case LTsquare:
  2454. case LTcircle:
  2455. s = _newstr(1);
  2456. s[0] = (ty == LTdisc)? 0x2022 // bullet
  2457. : ((ty == LTsquare)? 0x220e // filled square
  2458. : 0x2218); // degree
  2459. s[1] = 0;
  2460. break;
  2461. case LT1:
  2462. s = runesmprint("%d.", n);
  2463. break;
  2464. case LTa:
  2465. case LTA:
  2466. n--;
  2467. i = 0;
  2468. if(n < 0)
  2469. n = 0;
  2470. s = _newstr((n <= 25)? 2 : 3);
  2471. if(n > 25) {
  2472. n2 = n%26;
  2473. n /= 26;
  2474. if(n2 > 25)
  2475. n2 = 25;
  2476. s[i++] = n2 + (ty == LTa)? 'a' : 'A';
  2477. }
  2478. s[i++] = n + (ty == LTa)? 'a' : 'A';
  2479. s[i++] = '.';
  2480. s[i] = 0;
  2481. break;
  2482. case LTi:
  2483. case LTI:
  2484. if(n >= NROMAN) {
  2485. if(warn)
  2486. fprint(2, "warning: unimplemented roman number > %d\n", NROMAN);
  2487. n = NROMAN;
  2488. }
  2489. t = roman[n - 1];
  2490. n2 = _Strlen(t);
  2491. s = _newstr(n2+1);
  2492. for(i = 0; i < n2; i++)
  2493. s[i] = (ty == LTi)? tolower(t[i]) : t[i];
  2494. s[i++] = '.';
  2495. s[i] = 0;
  2496. break;
  2497. }
  2498. return s;
  2499. }
  2500. // Find map with given name in di.maps.
  2501. // If not there, add one, copying name.
  2502. // Ownership of map remains with di->maps list.
  2503. static Map*
  2504. getmap(Docinfo* di, Rune* name)
  2505. {
  2506. Map* m;
  2507. for(m = di->maps; m != nil; m = m->next) {
  2508. if(!_Strcmp(name, m->name))
  2509. return m;
  2510. }
  2511. m = (Map*)emalloc(sizeof(Map));
  2512. m->name = _Strdup(name);
  2513. m->areas = nil;
  2514. m->next = di->maps;
  2515. di->maps = m;
  2516. return m;
  2517. }
  2518. // Transfers ownership of href to Area
  2519. static Area*
  2520. newarea(int shape, Rune* href, int target, Area* link)
  2521. {
  2522. Area* a;
  2523. a = (Area*)emalloc(sizeof(Area));
  2524. a->shape = shape;
  2525. a->href = href;
  2526. a->target = target;
  2527. a->next = link;
  2528. return a;
  2529. }
  2530. // Return string value associated with attid in tok, nil if none.
  2531. // Caller must free the result (eventually).
  2532. static Rune*
  2533. aval(Token* tok, int attid)
  2534. {
  2535. Rune* ans;
  2536. _tokaval(tok, attid, &ans, 1); // transfers string ownership from token to ans
  2537. return ans;
  2538. }
  2539. // Like aval, but use dflt if there was no such attribute in tok.
  2540. // Caller must free the result (eventually).
  2541. static Rune*
  2542. astrval(Token* tok, int attid, Rune* dflt)
  2543. {
  2544. Rune* ans;
  2545. if(_tokaval(tok, attid, &ans, 1))
  2546. return ans; // transfers string ownership from token to ans
  2547. else
  2548. return _Strdup(dflt);
  2549. }
  2550. // Here we're supposed to convert to an int,
  2551. // and have a default when not found
  2552. static int
  2553. aintval(Token* tok, int attid, int dflt)
  2554. {
  2555. Rune* ans;
  2556. if(!_tokaval(tok, attid, &ans, 0) || ans == nil)
  2557. return dflt;
  2558. else
  2559. return toint(ans);
  2560. }
  2561. // Like aintval, but result should be >= 0
  2562. static int
  2563. auintval(Token* tok, int attid, int dflt)
  2564. {
  2565. Rune* ans;
  2566. int v;
  2567. if(!_tokaval(tok, attid, &ans, 0) || ans == nil)
  2568. return dflt;
  2569. else {
  2570. v = toint(ans);
  2571. return v >= 0? v : 0;
  2572. }
  2573. }
  2574. // int conversion, but with possible error check (if warning)
  2575. static int
  2576. toint(Rune* s)
  2577. {
  2578. int ans;
  2579. Rune* eptr;
  2580. ans = _Strtol(s, &eptr, 10);
  2581. if(warn) {
  2582. if(*eptr != 0) {
  2583. eptr = _Strclass(eptr, notwhitespace);
  2584. if(eptr != nil)
  2585. fprint(2, "warning: expected integer, got %S\n", s);
  2586. }
  2587. }
  2588. return ans;
  2589. }
  2590. // Attribute value when need a table to convert strings to ints
  2591. static int
  2592. atabval(Token* tok, int attid, StringInt* tab, int ntab, int dflt)
  2593. {
  2594. Rune* aval;
  2595. int ans;
  2596. ans = dflt;
  2597. if(_tokaval(tok, attid, &aval, 0)) {
  2598. if(!_lookup(tab, ntab, aval, _Strlen(aval), &ans)) {
  2599. ans = dflt;
  2600. if(warn)
  2601. fprint(2, "warning: name not found in table lookup: %S\n", aval);
  2602. }
  2603. }
  2604. return ans;
  2605. }
  2606. // Attribute value when supposed to be a color
  2607. static int
  2608. acolorval(Token* tok, int attid, int dflt)
  2609. {
  2610. Rune* aval;
  2611. int ans;
  2612. ans = dflt;
  2613. if(_tokaval(tok, attid, &aval, 0))
  2614. ans = color(aval, dflt);
  2615. return ans;
  2616. }
  2617. // Attribute value when supposed to be a target frame name
  2618. static int
  2619. atargval(Token* tok, int dflt)
  2620. {
  2621. int ans;
  2622. Rune* aval;
  2623. ans = dflt;
  2624. if(_tokaval(tok, Atarget, &aval, 0)){
  2625. ans = targetid(aval);
  2626. }
  2627. return ans;
  2628. }
  2629. // special for list types, where "i" and "I" are different,
  2630. // but "square" and "SQUARE" are the same
  2631. static int
  2632. listtyval(Token* tok, int dflt)
  2633. {
  2634. Rune* aval;
  2635. int ans;
  2636. int n;
  2637. ans = dflt;
  2638. if(_tokaval(tok, Atype, &aval, 0)) {
  2639. n = _Strlen(aval);
  2640. if(n == 1) {
  2641. switch(aval[0]) {
  2642. case '1':
  2643. ans = LT1;
  2644. break;
  2645. case 'A':
  2646. ans = LTA;
  2647. break;
  2648. case 'I':
  2649. ans = LTI;
  2650. break;
  2651. case 'a':
  2652. ans = LTa;
  2653. break;
  2654. case 'i':
  2655. ans = LTi;
  2656. default:
  2657. if(warn)
  2658. fprint(2, "warning: unknown list element type %c\n", aval[0]);
  2659. }
  2660. }
  2661. else {
  2662. if(!_Strncmpci(aval, n, L"circle"))
  2663. ans = LTcircle;
  2664. else if(!_Strncmpci(aval, n, L"disc"))
  2665. ans = LTdisc;
  2666. else if(!_Strncmpci(aval, n, L"square"))
  2667. ans = LTsquare;
  2668. else {
  2669. if(warn)
  2670. fprint(2, "warning: unknown list element type %S\n", aval);
  2671. }
  2672. }
  2673. }
  2674. return ans;
  2675. }
  2676. // Attribute value when value is a URL, possibly relative to base.
  2677. // FOR NOW: leave the url relative.
  2678. // Caller must free the result (eventually).
  2679. static Rune*
  2680. aurlval(Token* tok, int attid, Rune* dflt, Rune* base)
  2681. {
  2682. Rune* ans;
  2683. Rune* url;
  2684. USED(base);
  2685. ans = nil;
  2686. if(_tokaval(tok, attid, &url, 0) && url != nil)
  2687. ans = removeallwhite(url);
  2688. if(ans == nil)
  2689. ans = _Strdup(dflt);
  2690. return ans;
  2691. }
  2692. // Return copy of s but with all whitespace (even internal) removed.
  2693. // This fixes some buggy URL specification strings.
  2694. static Rune*
  2695. removeallwhite(Rune* s)
  2696. {
  2697. int j;
  2698. int n;
  2699. int i;
  2700. int c;
  2701. Rune* ans;
  2702. j = 0;
  2703. n = _Strlen(s);
  2704. for(i = 0; i < n; i++) {
  2705. c = s[i];
  2706. if(c >= 256 || !isspace(c))
  2707. j++;
  2708. }
  2709. if(j < n) {
  2710. ans = _newstr(j);
  2711. j = 0;
  2712. for(i = 0; i < n; i++) {
  2713. c = s[i];
  2714. if(c >= 256 || !isspace(c))
  2715. ans[j++] = c;
  2716. }
  2717. ans[j] = 0;
  2718. }
  2719. else
  2720. ans = _Strdup(s);
  2721. return ans;
  2722. }
  2723. // Attribute value when mere presence of attr implies value of 1,
  2724. // but if there is an integer there, return it as the value.
  2725. static int
  2726. aflagval(Token* tok, int attid)
  2727. {
  2728. int val;
  2729. Rune* sval;
  2730. val = 0;
  2731. if(_tokaval(tok, attid, &sval, 0)) {
  2732. val = 1;
  2733. if(sval != nil)
  2734. val = toint(sval);
  2735. }
  2736. return val;
  2737. }
  2738. static Align
  2739. makealign(int halign, int valign)
  2740. {
  2741. Align al;
  2742. al.halign = halign;
  2743. al.valign = valign;
  2744. return al;
  2745. }
  2746. // Make an Align (two alignments, horizontal and vertical)
  2747. static Align
  2748. aalign(Token* tok)
  2749. {
  2750. return makealign(
  2751. atabval(tok, Aalign, align_tab, NALIGNTAB, ALnone),
  2752. atabval(tok, Avalign, align_tab, NALIGNTAB, ALnone));
  2753. }
  2754. // Make a Dimen, based on value of attid attr
  2755. static Dimen
  2756. adimen(Token* tok, int attid)
  2757. {
  2758. Rune* wd;
  2759. if(_tokaval(tok, attid, &wd, 0))
  2760. return parsedim(wd, _Strlen(wd));
  2761. else
  2762. return makedimen(Dnone, 0);
  2763. }
  2764. // Parse s[0:n] as num[.[num]][unit][%|*]
  2765. static Dimen
  2766. parsedim(Rune* s, int ns)
  2767. {
  2768. int kind;
  2769. int spec;
  2770. Rune* l;
  2771. int nl;
  2772. Rune* r;
  2773. int nr;
  2774. int mul;
  2775. int i;
  2776. Rune* f;
  2777. int nf;
  2778. int Tkdpi;
  2779. Rune* units;
  2780. kind = Dnone;
  2781. spec = 0;
  2782. _splitl(s, ns, L"^0-9", &l, &nl, &r, &nr);
  2783. if(nl != 0) {
  2784. spec = 1000*_Strtol(l, nil, 10);
  2785. if(nr > 0 && r[0] == '.') {
  2786. _splitl(r+1, nr-1, L"^0-9", &f, &nf, &r, &nr);
  2787. if(nf != 0) {
  2788. mul = 100;
  2789. for(i = 0; i < nf; i++) {
  2790. spec = spec + mul*(f[i]-'0');
  2791. mul = mul/10;
  2792. }
  2793. }
  2794. }
  2795. kind = Dpixels;
  2796. if(nr != 0) {
  2797. if(nr >= 2) {
  2798. Tkdpi = 100;
  2799. units = r;
  2800. r = r+2;
  2801. nr -= 2;
  2802. if(!_Strncmpci(units, 2, L"pt"))
  2803. spec = (spec*Tkdpi)/72;
  2804. else if(!_Strncmpci(units, 2, L"pi"))
  2805. spec = (spec*12*Tkdpi)/72;
  2806. else if(!_Strncmpci(units, 2, L"in"))
  2807. spec = spec*Tkdpi;
  2808. else if(!_Strncmpci(units, 2, L"cm"))
  2809. spec = (spec*100*Tkdpi)/254;
  2810. else if(!_Strncmpci(units, 2, L"mm"))
  2811. spec = (spec*10*Tkdpi)/254;
  2812. else if(!_Strncmpci(units, 2, L"em"))
  2813. spec = spec*15;
  2814. else {
  2815. if(warn)
  2816. fprint(2, "warning: unknown units %C%Cs\n", units[0], units[1]);
  2817. }
  2818. }
  2819. if(nr >= 1) {
  2820. if(r[0] == '%')
  2821. kind = Dpercent;
  2822. else if(r[0] == '*')
  2823. kind = Drelative;
  2824. }
  2825. }
  2826. spec = spec/1000;
  2827. }
  2828. else if(nr == 1 && r[0] == '*') {
  2829. spec = 1;
  2830. kind = Drelative;
  2831. }
  2832. return makedimen(kind, spec);
  2833. }
  2834. static void
  2835. setdimarray(Token* tok, int attid, Dimen** pans, int* panslen)
  2836. {
  2837. Rune* s;
  2838. Dimen* d;
  2839. int k;
  2840. int nc;
  2841. Rune* a[SMALLBUFSIZE];
  2842. int an[SMALLBUFSIZE];
  2843. if(_tokaval(tok, attid, &s, 0)) {
  2844. nc = _splitall(s, _Strlen(s), L", ", a, an, SMALLBUFSIZE);
  2845. if(nc > 0) {
  2846. d = (Dimen*)emalloc(nc * sizeof(Dimen));
  2847. for(k = 0; k < nc; k++) {
  2848. d[k] = parsedim(a[k], an[k]);
  2849. }
  2850. *pans = d;
  2851. *panslen = nc;
  2852. return;
  2853. }
  2854. }
  2855. *pans = nil;
  2856. *panslen = 0;
  2857. }
  2858. static Background
  2859. makebackground(Rune* imageurl, int color)
  2860. {
  2861. Background bg;
  2862. bg.image = imageurl;
  2863. bg.color = color;
  2864. return bg;
  2865. }
  2866. static Item*
  2867. newitext(Rune* s, int fnt, int fg, int voff, int ul)
  2868. {
  2869. Itext* t;
  2870. assert(s != nil);
  2871. t = (Itext*)emalloc(sizeof(Itext));
  2872. t->tag = Itexttag;
  2873. t->s = s;
  2874. t->fnt = fnt;
  2875. t->fg = fg;
  2876. t->voff = voff;
  2877. t->ul = ul;
  2878. return (Item*)t;
  2879. }
  2880. static Item*
  2881. newirule(int align, int size, int noshade, int color, Dimen wspec)
  2882. {
  2883. Irule* r;
  2884. r = (Irule*)emalloc(sizeof(Irule));
  2885. r->tag = Iruletag;
  2886. r->align = align;
  2887. r->size = size;
  2888. r->noshade = noshade;
  2889. r->color = color;
  2890. r->wspec = wspec;
  2891. return (Item*)r;
  2892. }
  2893. // Map is owned elsewhere.
  2894. static Item*
  2895. newiimage(Rune* src, Rune* altrep, int align, int width, int height,
  2896. int hspace, int vspace, int border, int ismap, Map* map)
  2897. {
  2898. Iimage* i;
  2899. int state;
  2900. state = 0;
  2901. if(ismap)
  2902. state = IFsmap;
  2903. i = (Iimage*)emalloc(sizeof(Iimage));
  2904. i->tag = Iimagetag;
  2905. i->state = state;
  2906. i->imsrc = src;
  2907. i->altrep = altrep;
  2908. i->align = align;
  2909. i->imwidth = width;
  2910. i->imheight = height;
  2911. i->hspace = hspace;
  2912. i->vspace = vspace;
  2913. i->border = border;
  2914. i->map = map;
  2915. i->ctlid = -1;
  2916. return (Item*)i;
  2917. }
  2918. static Item*
  2919. newiformfield(Formfield* ff)
  2920. {
  2921. Iformfield* f;
  2922. f = (Iformfield*)emalloc(sizeof(Iformfield));
  2923. f->tag = Iformfieldtag;
  2924. f->formfield = ff;
  2925. return (Item*)f;
  2926. }
  2927. static Item*
  2928. newitable(Table* tab)
  2929. {
  2930. Itable* t;
  2931. t = (Itable*)emalloc(sizeof(Itable));
  2932. t->tag = Itabletag;
  2933. t->table = tab;
  2934. return (Item*)t;
  2935. }
  2936. static Item*
  2937. newifloat(Item* it, int side)
  2938. {
  2939. Ifloat* f;
  2940. f = (Ifloat*)emalloc(sizeof(Ifloat));
  2941. f->tag = Ifloattag;
  2942. f->state = IFwrap;
  2943. f->item = it;
  2944. f->side = side;
  2945. return (Item*)f;
  2946. }
  2947. static Item*
  2948. newispacer(int spkind)
  2949. {
  2950. Ispacer* s;
  2951. s = (Ispacer*)emalloc(sizeof(Ispacer));
  2952. s->tag = Ispacertag;
  2953. s->spkind = spkind;
  2954. return (Item*)s;
  2955. }
  2956. // Free one item (caller must deal with next pointer)
  2957. static void
  2958. freeitem(Item* it)
  2959. {
  2960. Iimage* ii;
  2961. Genattr* ga;
  2962. if(it == nil)
  2963. return;
  2964. switch(it->tag) {
  2965. case Itexttag:
  2966. free(((Itext*)it)->s);
  2967. break;
  2968. case Iimagetag:
  2969. ii = (Iimage*)it;
  2970. free(ii->imsrc);
  2971. free(ii->altrep);
  2972. break;
  2973. case Iformfieldtag:
  2974. freeformfield(((Iformfield*)it)->formfield);
  2975. break;
  2976. case Itabletag:
  2977. freetable(((Itable*)it)->table);
  2978. break;
  2979. case Ifloattag:
  2980. freeitem(((Ifloat*)it)->item);
  2981. break;
  2982. }
  2983. ga = it->genattr;
  2984. if(ga != nil) {
  2985. free(ga->id);
  2986. free(ga->class);
  2987. free(ga->style);
  2988. free(ga->title);
  2989. freescriptevents(ga->events);
  2990. }
  2991. free(it);
  2992. }
  2993. // Free list of items chained through next pointer
  2994. void
  2995. freeitems(Item* ithead)
  2996. {
  2997. Item* it;
  2998. Item* itnext;
  2999. it = ithead;
  3000. while(it != nil) {
  3001. itnext = it->next;
  3002. freeitem(it);
  3003. it = itnext;
  3004. }
  3005. }
  3006. static void
  3007. freeformfield(Formfield* ff)
  3008. {
  3009. Option* o;
  3010. Option* onext;
  3011. if(ff == nil)
  3012. return;
  3013. free(ff->name);
  3014. free(ff->value);
  3015. for(o = ff->options; o != nil; o = onext) {
  3016. onext = o->next;
  3017. free(o->value);
  3018. free(o->display);
  3019. }
  3020. free(ff);
  3021. }
  3022. static void
  3023. freetable(Table* t)
  3024. {
  3025. int i;
  3026. Tablecell* c;
  3027. Tablecell* cnext;
  3028. if(t == nil)
  3029. return;
  3030. // We'll find all the unique cells via t->cells and next pointers.
  3031. // (Other pointers to cells in the table are duplicates of these)
  3032. for(c = t->cells; c != nil; c = cnext) {
  3033. cnext = c->next;
  3034. freeitems(c->content);
  3035. }
  3036. if(t->grid != nil) {
  3037. for(i = 0; i < t->nrow; i++)
  3038. free(t->grid[i]);
  3039. free(t->grid);
  3040. }
  3041. free(t->rows);
  3042. free(t->cols);
  3043. freeitems(t->caption);
  3044. free(t);
  3045. }
  3046. static void
  3047. freeform(Form* f)
  3048. {
  3049. if(f == nil)
  3050. return;
  3051. free(f->name);
  3052. free(f->action);
  3053. // Form doesn't own its fields (Iformfield items do)
  3054. free(f);
  3055. }
  3056. static void
  3057. freeforms(Form* fhead)
  3058. {
  3059. Form* f;
  3060. Form* fnext;
  3061. for(f = fhead; f != nil; f = fnext) {
  3062. fnext = f->next;
  3063. freeform(f);
  3064. }
  3065. }
  3066. static void
  3067. freeanchor(Anchor* a)
  3068. {
  3069. if(a == nil)
  3070. return;
  3071. free(a->name);
  3072. free(a->href);
  3073. free(a);
  3074. }
  3075. static void
  3076. freeanchors(Anchor* ahead)
  3077. {
  3078. Anchor* a;
  3079. Anchor* anext;
  3080. for(a = ahead; a != nil; a = anext) {
  3081. anext = a->next;
  3082. freeanchor(a);
  3083. }
  3084. }
  3085. static void
  3086. freedestanchor(DestAnchor* da)
  3087. {
  3088. if(da == nil)
  3089. return;
  3090. free(da->name);
  3091. free(da);
  3092. }
  3093. static void
  3094. freedestanchors(DestAnchor* dahead)
  3095. {
  3096. DestAnchor* da;
  3097. DestAnchor* danext;
  3098. for(da = dahead; da != nil; da = danext) {
  3099. danext = da->next;
  3100. freedestanchor(da);
  3101. }
  3102. }
  3103. static void
  3104. freearea(Area* a)
  3105. {
  3106. if(a == nil)
  3107. return;
  3108. free(a->href);
  3109. free(a->coords);
  3110. }
  3111. static void freekidinfos(Kidinfo* khead);
  3112. static void
  3113. freekidinfo(Kidinfo* k)
  3114. {
  3115. if(k->isframeset) {
  3116. free(k->rows);
  3117. free(k->cols);
  3118. freekidinfos(k->kidinfos);
  3119. }
  3120. else {
  3121. free(k->src);
  3122. free(k->name);
  3123. }
  3124. free(k);
  3125. }
  3126. static void
  3127. freekidinfos(Kidinfo* khead)
  3128. {
  3129. Kidinfo* k;
  3130. Kidinfo* knext;
  3131. for(k = khead; k != nil; k = knext) {
  3132. knext = k->next;
  3133. freekidinfo(k);
  3134. }
  3135. }
  3136. static void
  3137. freemap(Map* m)
  3138. {
  3139. Area* a;
  3140. Area* anext;
  3141. if(m == nil)
  3142. return;
  3143. free(m->name);
  3144. for(a = m->areas; a != nil; a = anext) {
  3145. anext = a->next;
  3146. freearea(a);
  3147. }
  3148. free(m);
  3149. }
  3150. static void
  3151. freemaps(Map* mhead)
  3152. {
  3153. Map* m;
  3154. Map* mnext;
  3155. for(m = mhead; m != nil; m = mnext) {
  3156. mnext = m->next;
  3157. freemap(m);
  3158. }
  3159. }
  3160. void
  3161. freedocinfo(Docinfo* d)
  3162. {
  3163. if(d == nil)
  3164. return;
  3165. free(d->src);
  3166. free(d->base);
  3167. freeitem((Item*)d->backgrounditem);
  3168. free(d->refresh);
  3169. freekidinfos(d->kidinfo);
  3170. freeanchors(d->anchors);
  3171. freedestanchors(d->dests);
  3172. freeforms(d->forms);
  3173. freemaps(d->maps);
  3174. // tables, images, and formfields are freed when
  3175. // the items pointing at them are freed
  3176. free(d);
  3177. }
  3178. // Currently, someone else owns all the memory
  3179. // pointed to by things in a Pstate.
  3180. static void
  3181. freepstate(Pstate* p)
  3182. {
  3183. free(p);
  3184. }
  3185. static void
  3186. freepstatestack(Pstate* pshead)
  3187. {
  3188. Pstate* p;
  3189. Pstate* pnext;
  3190. for(p = pshead; p != nil; p = pnext) {
  3191. pnext = p->next;
  3192. free(p);
  3193. }
  3194. }
  3195. static int
  3196. Iconv(Fmt *f)
  3197. {
  3198. Item* it;
  3199. Itext* t;
  3200. Irule* r;
  3201. Iimage* i;
  3202. Ifloat* fl;
  3203. int state;
  3204. Formfield* ff;
  3205. Rune* ty;
  3206. Tablecell* c;
  3207. Table* tab;
  3208. char* p;
  3209. int cl;
  3210. int hang;
  3211. int indent;
  3212. int bi;
  3213. int nbuf;
  3214. char buf[BIGBUFSIZE];
  3215. it = va_arg(f->args, Item*);
  3216. bi = 0;
  3217. nbuf = sizeof(buf);
  3218. state = it->state;
  3219. nbuf = nbuf-1;
  3220. if(state&IFbrk) {
  3221. cl = state&(IFcleft|IFcright);
  3222. p = "";
  3223. if(cl) {
  3224. if(cl == (IFcleft|IFcright))
  3225. p = " both";
  3226. else if(cl == IFcleft)
  3227. p = " left";
  3228. else
  3229. p = " right";
  3230. }
  3231. bi = snprint(buf, nbuf, "brk(%d%s)", (state&IFbrksp)? 1 : 0, p);
  3232. }
  3233. if(state&IFnobrk)
  3234. bi += snprint(buf+bi, nbuf-bi, " nobrk");
  3235. if(!(state&IFwrap))
  3236. bi += snprint(buf+bi, nbuf-bi, " nowrap");
  3237. if(state&IFrjust)
  3238. bi += snprint(buf+bi, nbuf-bi, " rjust");
  3239. if(state&IFcjust)
  3240. bi += snprint(buf+bi, nbuf-bi, " cjust");
  3241. if(state&IFsmap)
  3242. bi += snprint(buf+bi, nbuf-bi, " smap");
  3243. indent = (state&IFindentmask) >> IFindentshift;
  3244. if(indent > 0)
  3245. bi += snprint(buf+bi, nbuf-bi, " indent=%d", indent);
  3246. hang = state&IFhangmask;
  3247. if(hang > 0)
  3248. bi += snprint(buf+bi, nbuf-bi, " hang=%d", hang);
  3249. switch(it->tag) {
  3250. case Itexttag:
  3251. t = (Itext*)it;
  3252. bi += snprint(buf+bi, nbuf-bi, " Text '%S', fnt=%d, fg=%x", t->s, t->fnt, t->fg);
  3253. break;
  3254. case Iruletag:
  3255. r = (Irule*)it;
  3256. bi += snprint(buf+bi, nbuf-bi, "Rule size=%d, al=%S, wspec=", r->size, stringalign(r->align));
  3257. bi += dimprint(buf+bi, nbuf-bi, r->wspec);
  3258. break;
  3259. case Iimagetag:
  3260. i = (Iimage*)it;
  3261. bi += snprint(buf+bi, nbuf-bi,
  3262. "Image src=%S, alt=%S, al=%S, w=%d, h=%d hsp=%d, vsp=%d, bd=%d, map=%S",
  3263. i->imsrc, i->altrep? i->altrep : L"", stringalign(i->align), i->imwidth, i->imheight,
  3264. i->hspace, i->vspace, i->border, i->map? i->map->name : L"");
  3265. break;
  3266. case Iformfieldtag:
  3267. ff = ((Iformfield*)it)->formfield;
  3268. if(ff->ftype == Ftextarea)
  3269. ty = L"textarea";
  3270. else if(ff->ftype == Fselect)
  3271. ty = L"select";
  3272. else {
  3273. ty = _revlookup(input_tab, NINPUTTAB, ff->ftype);
  3274. if(ty == nil)
  3275. ty = L"none";
  3276. }
  3277. bi += snprint(buf+bi, nbuf-bi, "Formfield %S, fieldid=%d, formid=%d, name=%S, value=%S",
  3278. ty, ff->fieldid, ff->form->formid, ff->name? ff->name : L"",
  3279. ff->value? ff->value : L"");
  3280. break;
  3281. case Itabletag:
  3282. tab = ((Itable*)it)->table;
  3283. bi += snprint(buf+bi, nbuf-bi, "Table tableid=%d, width=", tab->tableid);
  3284. bi += dimprint(buf+bi, nbuf-bi, tab->width);
  3285. bi += snprint(buf+bi, nbuf-bi, ", nrow=%d, ncol=%d, ncell=%d, totw=%d, toth=%d\n",
  3286. tab->nrow, tab->ncol, tab->ncell, tab->totw, tab->toth);
  3287. for(c = tab->cells; c != nil; c = c->next)
  3288. bi += snprint(buf+bi, nbuf-bi, "Cell %d.%d, at (%d,%d) ",
  3289. tab->tableid, c->cellid, c->row, c->col);
  3290. bi += snprint(buf+bi, nbuf-bi, "End of Table %d", tab->tableid);
  3291. break;
  3292. case Ifloattag:
  3293. fl = (Ifloat*)it;
  3294. bi += snprint(buf+bi, nbuf-bi, "Float, x=%d y=%d, side=%S, it=%I",
  3295. fl->x, fl->y, stringalign(fl->side), fl->item);
  3296. bi += snprint(buf+bi, nbuf-bi, "\n\t");
  3297. break;
  3298. case Ispacertag:
  3299. p = "";
  3300. switch(((Ispacer*)it)->spkind) {
  3301. case ISPnull:
  3302. p = "null";
  3303. break;
  3304. case ISPvline:
  3305. p = "vline";
  3306. break;
  3307. case ISPhspace:
  3308. p = "hspace";
  3309. break;
  3310. }
  3311. bi += snprint(buf+bi, nbuf-bi, "Spacer %s ", p);
  3312. break;
  3313. }
  3314. bi += snprint(buf+bi, nbuf-bi, " w=%d, h=%d, a=%d, anchor=%d\n",
  3315. it->width, it->height, it->ascent, it->anchorid);
  3316. buf[bi] = 0;
  3317. return fmtstrcpy(f, buf);
  3318. }
  3319. // String version of alignment 'a'
  3320. static Rune*
  3321. stringalign(int a)
  3322. {
  3323. Rune* s;
  3324. s = _revlookup(align_tab, NALIGNTAB, a);
  3325. if(s == nil)
  3326. s = L"none";
  3327. return s;
  3328. }
  3329. // Put at most nbuf chars of representation of d into buf,
  3330. // and return number of characters put
  3331. static int
  3332. dimprint(char* buf, int nbuf, Dimen d)
  3333. {
  3334. int n;
  3335. int k;
  3336. n = 0;
  3337. n += snprint(buf, nbuf, "%d", dimenspec(d));
  3338. k = dimenkind(d);
  3339. if(k == Dpercent)
  3340. buf[n++] = '%';
  3341. if(k == Drelative)
  3342. buf[n++] = '*';
  3343. return n;
  3344. }
  3345. void
  3346. printitems(Item* items, char* msg)
  3347. {
  3348. Item* il;
  3349. fprint(2, "%s\n", msg);
  3350. il = items;
  3351. while(il != nil) {
  3352. fprint(2, "%I", il);
  3353. il = il->next;
  3354. }
  3355. }
  3356. static Genattr*
  3357. newgenattr(Rune* id, Rune* class, Rune* style, Rune* title, SEvent* events)
  3358. {
  3359. Genattr* g;
  3360. g = (Genattr*)emalloc(sizeof(Genattr));
  3361. g->id = id;
  3362. g->class = class;
  3363. g->style = style;
  3364. g->title = title;
  3365. g->events = events;
  3366. return g;
  3367. }
  3368. static Formfield*
  3369. newformfield(int ftype, int fieldid, Form* form, Rune* name,
  3370. Rune* value, int size, int maxlength, Formfield* link)
  3371. {
  3372. Formfield* ff;
  3373. ff = (Formfield*)emalloc(sizeof(Formfield));
  3374. ff->ftype = ftype;
  3375. ff->fieldid = fieldid;
  3376. ff->form = form;
  3377. ff->name = name;
  3378. ff->value = value;
  3379. ff->size = size;
  3380. ff->maxlength = maxlength;
  3381. ff->ctlid = -1;
  3382. ff->next = link;
  3383. return ff;
  3384. }
  3385. // Transfers ownership of value and display to Option.
  3386. static Option*
  3387. newoption(int selected, Rune* value, Rune* display, Option* link)
  3388. {
  3389. Option *o;
  3390. o = (Option*)emalloc(sizeof(Option));
  3391. o->selected = selected;
  3392. o->value = value;
  3393. o->display = display;
  3394. o->next = link;
  3395. return o;
  3396. }
  3397. static Form*
  3398. newform(int formid, Rune* name, Rune* action, int target, int method, Form* link)
  3399. {
  3400. Form* f;
  3401. f = (Form*)emalloc(sizeof(Form));
  3402. f->formid = formid;
  3403. f->name = name;
  3404. f->action = action;
  3405. f->target = target;
  3406. f->method = method;
  3407. f->nfields = 0;
  3408. f->fields = nil;
  3409. f->next = link;
  3410. return f;
  3411. }
  3412. static Table*
  3413. newtable(int tableid, Align align, Dimen width, int border,
  3414. int cellspacing, int cellpadding, Background bg, Token* tok, Table* link)
  3415. {
  3416. Table* t;
  3417. t = (Table*)emalloc(sizeof(Table));
  3418. t->tableid = tableid;
  3419. t->align = align;
  3420. t->width = width;
  3421. t->border = border;
  3422. t->cellspacing = cellspacing;
  3423. t->cellpadding = cellpadding;
  3424. t->background = bg;
  3425. t->caption_place = ALbottom;
  3426. t->caption_lay = nil;
  3427. t->tabletok = tok;
  3428. t->tabletok = nil;
  3429. t->next = link;
  3430. return t;
  3431. }
  3432. static Tablerow*
  3433. newtablerow(Align align, Background bg, int flags, Tablerow* link)
  3434. {
  3435. Tablerow* tr;
  3436. tr = (Tablerow*)emalloc(sizeof(Tablerow));
  3437. tr->align = align;
  3438. tr->background = bg;
  3439. tr->flags = flags;
  3440. tr->next = link;
  3441. return tr;
  3442. }
  3443. static Tablecell*
  3444. newtablecell(int cellid, int rowspan, int colspan, Align align, Dimen wspec, int hspec,
  3445. Background bg, int flags, Tablecell* link)
  3446. {
  3447. Tablecell* c;
  3448. c = (Tablecell*)emalloc(sizeof(Tablecell));
  3449. c->cellid = cellid;
  3450. c->lay = nil;
  3451. c->rowspan = rowspan;
  3452. c->colspan = colspan;
  3453. c->align = align;
  3454. c->flags = flags;
  3455. c->wspec = wspec;
  3456. c->hspec = hspec;
  3457. c->background = bg;
  3458. c->next = link;
  3459. return c;
  3460. }
  3461. static Anchor*
  3462. newanchor(int index, Rune* name, Rune* href, int target, Anchor* link)
  3463. {
  3464. Anchor* a;
  3465. a = (Anchor*)emalloc(sizeof(Anchor));
  3466. a->index = index;
  3467. a->name = name;
  3468. a->href = href;
  3469. a->target = target;
  3470. a->next = link;
  3471. return a;
  3472. }
  3473. static DestAnchor*
  3474. newdestanchor(int index, Rune* name, Item* item, DestAnchor* link)
  3475. {
  3476. DestAnchor* d;
  3477. d = (DestAnchor*)emalloc(sizeof(DestAnchor));
  3478. d->index = index;
  3479. d->name = name;
  3480. d->item = item;
  3481. d->next = link;
  3482. return d;
  3483. }
  3484. static SEvent*
  3485. newscriptevent(int type, Rune* script, SEvent* link)
  3486. {
  3487. SEvent* ans;
  3488. ans = (SEvent*)emalloc(sizeof(SEvent));
  3489. ans->type = type;
  3490. ans->script = script;
  3491. ans->next = link;
  3492. return ans;
  3493. }
  3494. static void
  3495. freescriptevents(SEvent* ehead)
  3496. {
  3497. SEvent* e;
  3498. SEvent* nexte;
  3499. e = ehead;
  3500. while(e != nil) {
  3501. nexte = e->next;
  3502. free(e->script);
  3503. free(e);
  3504. e = nexte;
  3505. }
  3506. }
  3507. static Dimen
  3508. makedimen(int kind, int spec)
  3509. {
  3510. Dimen d;
  3511. if(spec&Dkindmask) {
  3512. if(warn)
  3513. fprint(2, "warning: dimension spec too big: %d\n", spec);
  3514. spec = 0;
  3515. }
  3516. d.kindspec = kind|spec;
  3517. return d;
  3518. }
  3519. int
  3520. dimenkind(Dimen d)
  3521. {
  3522. return (d.kindspec&Dkindmask);
  3523. }
  3524. int
  3525. dimenspec(Dimen d)
  3526. {
  3527. return (d.kindspec&Dspecmask);
  3528. }
  3529. static Kidinfo*
  3530. newkidinfo(int isframeset, Kidinfo* link)
  3531. {
  3532. Kidinfo* ki;
  3533. ki = (Kidinfo*)emalloc(sizeof(Kidinfo));
  3534. ki->isframeset = isframeset;
  3535. if(!isframeset) {
  3536. ki->flags = FRhscrollauto|FRvscrollauto;
  3537. ki->marginw = FRKIDMARGIN;
  3538. ki->marginh = FRKIDMARGIN;
  3539. ki->framebd = 1;
  3540. }
  3541. ki->next = link;
  3542. return ki;
  3543. }
  3544. static Docinfo*
  3545. newdocinfo(void)
  3546. {
  3547. Docinfo* d;
  3548. d = (Docinfo*)emalloc(sizeof(Docinfo));
  3549. resetdocinfo(d);
  3550. return d;
  3551. }
  3552. static void
  3553. resetdocinfo(Docinfo* d)
  3554. {
  3555. memset(d, 0, sizeof(Docinfo));
  3556. d->background = makebackground(nil, White);
  3557. d->text = Black;
  3558. d->link = Blue;
  3559. d->vlink = Blue;
  3560. d->alink = Blue;
  3561. d->target = FTself;
  3562. d->chset = ISO_8859_1;
  3563. d->scripttype = TextJavascript;
  3564. d->frameid = -1;
  3565. }
  3566. // Use targetmap array to keep track of name <-> targetid mapping.
  3567. // Use real malloc(), and never free
  3568. static void
  3569. targetmapinit(void)
  3570. {
  3571. int l;
  3572. targetmapsize = 10;
  3573. l = targetmapsize*sizeof *targetmap;
  3574. targetmap = emalloc(l);
  3575. memset(targetmap, 0, l);
  3576. targetmap[0].key = _Strdup(L"_top");
  3577. targetmap[0].val = FTtop;
  3578. targetmap[1].key = _Strdup(L"_self");
  3579. targetmap[1].val = FTself;
  3580. targetmap[2].key = _Strdup(L"_parent");
  3581. targetmap[2].val = FTparent;
  3582. targetmap[3].key = _Strdup(L"_blank");
  3583. targetmap[3].val = FTblank;
  3584. ntargets = 4;
  3585. }
  3586. int
  3587. targetid(Rune* s)
  3588. {
  3589. int i;
  3590. int n;
  3591. n = _Strlen(s);
  3592. if(n == 0)
  3593. return FTself;
  3594. for(i = 0; i < ntargets; i++)
  3595. if(_Strcmp(s, targetmap[i].key) == 0)
  3596. return targetmap[i].val;
  3597. if(i == targetmapsize) {
  3598. targetmapsize += 10;
  3599. targetmap = erealloc(targetmap, targetmapsize*sizeof(StringInt));
  3600. }
  3601. targetmap[i].key = _Strdup(s);
  3602. targetmap[i].val = i;
  3603. ntargets++;
  3604. return i;
  3605. }
  3606. Rune*
  3607. targetname(int targid)
  3608. {
  3609. int i;
  3610. for(i = 0; i < ntargets; i++)
  3611. if(targetmap[i].val == targid)
  3612. return targetmap[i].key;
  3613. return L"?";
  3614. }
  3615. // Convert HTML color spec to RGB value, returning dflt if can't.
  3616. // Argument is supposed to be a valid HTML color, or "".
  3617. // Return the RGB value of the color, using dflt if s
  3618. // is nil or an invalid color.
  3619. static int
  3620. color(Rune* s, int dflt)
  3621. {
  3622. int v;
  3623. Rune* rest;
  3624. if(s == nil)
  3625. return dflt;
  3626. if(_lookup(color_tab, NCOLORS, s, _Strlen(s), &v))
  3627. return v;
  3628. if(s[0] == '#')
  3629. s++;
  3630. v = _Strtol(s, &rest, 16);
  3631. if(*rest == 0)
  3632. return v;
  3633. return dflt;
  3634. }
  3635. // Debugging
  3636. #define HUGEPIX 10000
  3637. // A "shallow" validitem, that doesn't follow next links
  3638. // or descend into tables.
  3639. static int
  3640. validitem(Item* i)
  3641. {
  3642. int ok;
  3643. Itext* ti;
  3644. Irule* ri;
  3645. Iimage* ii;
  3646. Ifloat* fi;
  3647. int a;
  3648. ok = (i->tag >= Itexttag && i->tag <= Ispacertag) &&
  3649. (i->next == nil || validptr(i->next)) &&
  3650. (i->width >= 0 && i->width < HUGEPIX) &&
  3651. (i->height >= 0 && i->height < HUGEPIX) &&
  3652. (i->ascent > -HUGEPIX && i->ascent < HUGEPIX) &&
  3653. (i->anchorid >= 0) &&
  3654. (i->genattr == nil || validptr(i->genattr));
  3655. // also, could check state for ridiculous combinations
  3656. // also, could check anchorid for within-doc-range
  3657. if(ok)
  3658. switch(i->tag) {
  3659. case Itexttag:
  3660. ti = (Itext*)i;
  3661. ok = validStr(ti->s) &&
  3662. (ti->fnt >= 0 && ti->fnt < NumStyle*NumSize) &&
  3663. (ti->ul == ULnone || ti->ul == ULunder || ti->ul == ULmid);
  3664. break;
  3665. case Iruletag:
  3666. ri = (Irule*)i;
  3667. ok = (validvalign(ri->align) || validhalign(ri->align)) &&
  3668. (ri->size >=0 && ri->size < HUGEPIX);
  3669. break;
  3670. case Iimagetag:
  3671. ii = (Iimage*)i;
  3672. ok = (ii->imsrc == nil || validptr(ii->imsrc)) &&
  3673. (ii->width >= 0 && ii->width < HUGEPIX) &&
  3674. (ii->height >= 0 && ii->height < HUGEPIX) &&
  3675. (ii->imwidth >= 0 && ii->imwidth < HUGEPIX) &&
  3676. (ii->imheight >= 0 && ii->imheight < HUGEPIX) &&
  3677. (ii->altrep == nil || validStr(ii->altrep)) &&
  3678. (ii->map == nil || validptr(ii->map)) &&
  3679. (validvalign(ii->align) || validhalign(ii->align)) &&
  3680. (ii->nextimage == nil || validptr(ii->nextimage));
  3681. break;
  3682. case Iformfieldtag:
  3683. ok = validformfield(((Iformfield*)i)->formfield);
  3684. break;
  3685. case Itabletag:
  3686. ok = validptr((Itable*)i);
  3687. break;
  3688. case Ifloattag:
  3689. fi = (Ifloat*)i;
  3690. ok = (fi->side == ALleft || fi->side == ALright) &&
  3691. validitem(fi->item) &&
  3692. (fi->item->tag == Iimagetag || fi->item->tag == Itabletag);
  3693. break;
  3694. case Ispacertag:
  3695. a = ((Ispacer*)i)->spkind;
  3696. ok = a==ISPnull || a==ISPvline || a==ISPhspace || a==ISPgeneral;
  3697. break;
  3698. default:
  3699. ok = 0;
  3700. }
  3701. return ok;
  3702. }
  3703. // "deep" validation, that checks whole list of items,
  3704. // and descends into tables and floated tables.
  3705. // nil is ok for argument.
  3706. int
  3707. validitems(Item* i)
  3708. {
  3709. int ok;
  3710. Item* ii;
  3711. ok = 1;
  3712. while(i != nil && ok) {
  3713. ok = validitem(i);
  3714. if(ok) {
  3715. if(i->tag == Itabletag) {
  3716. ok = validtable(((Itable*)i)->table);
  3717. }
  3718. else if(i->tag == Ifloattag) {
  3719. ii = ((Ifloat*)i)->item;
  3720. if(ii->tag == Itabletag)
  3721. ok = validtable(((Itable*)ii)->table);
  3722. }
  3723. }
  3724. if(!ok) {
  3725. fprint(2, "invalid item: %I\n", i);
  3726. }
  3727. i = i->next;
  3728. }
  3729. return ok;
  3730. }
  3731. static int
  3732. validformfield(Formfield* f)
  3733. {
  3734. int ok;
  3735. ok = (f->next == nil || validptr(f->next)) &&
  3736. (f->ftype >= 0 && f->ftype <= Ftextarea) &&
  3737. f->fieldid >= 0 &&
  3738. (f->form == nil || validptr(f->form)) &&
  3739. (f->name == nil || validStr(f->name)) &&
  3740. (f->value == nil || validStr(f->value)) &&
  3741. (f->options == nil || validptr(f->options)) &&
  3742. (f->image == nil || validitem(f->image)) &&
  3743. (f->events == nil || validptr(f->events));
  3744. // when all built, should have f->fieldid < f->form->nfields,
  3745. // but this may be called during build...
  3746. return ok;
  3747. }
  3748. // "deep" validation -- checks cell contents too
  3749. static int
  3750. validtable(Table* t)
  3751. {
  3752. int ok;
  3753. int i, j;
  3754. Tablecell* c;
  3755. ok = (t->next == nil || validptr(t->next)) &&
  3756. t->nrow >= 0 &&
  3757. t->ncol >= 0 &&
  3758. t->ncell >= 0 &&
  3759. validalign(t->align) &&
  3760. validdimen(t->width) &&
  3761. (t->border >= 0 && t->border < HUGEPIX) &&
  3762. (t->cellspacing >= 0 && t->cellspacing < HUGEPIX) &&
  3763. (t->cellpadding >= 0 && t->cellpadding < HUGEPIX) &&
  3764. validitems(t->caption) &&
  3765. (t->caption_place == ALtop || t->caption_place == ALbottom) &&
  3766. (t->totw >= 0 && t->totw < HUGEPIX) &&
  3767. (t->toth >= 0 && t->toth < HUGEPIX) &&
  3768. (t->tabletok == nil || validptr(t->tabletok));
  3769. // during parsing, t->rows has list;
  3770. // only when parsing is done is t->nrow set > 0
  3771. if(ok && t->nrow > 0 && t->ncol > 0) {
  3772. // table is "finished"
  3773. for(i = 0; i < t->nrow && ok; i++)
  3774. ok = validtablerow(t->rows+i);
  3775. for(j = 0; j < t->ncol && ok; j++)
  3776. ok = validtablecol(t->cols+j);
  3777. for(c = t->cells; c != nil && ok; c = c->next)
  3778. ok = validtablecell(c);
  3779. for(i = 0; i < t->nrow && ok; i++)
  3780. for(j = 0; j < t->ncol && ok; j++)
  3781. ok = validptr(t->grid[i][j]);
  3782. }
  3783. return ok;
  3784. }
  3785. static int
  3786. validvalign(int a)
  3787. {
  3788. return a == ALnone || a == ALmiddle || a == ALbottom || a == ALtop || a == ALbaseline;
  3789. }
  3790. static int
  3791. validhalign(int a)
  3792. {
  3793. return a == ALnone || a == ALleft || a == ALcenter || a == ALright ||
  3794. a == ALjustify || a == ALchar;
  3795. }
  3796. static int
  3797. validalign(Align a)
  3798. {
  3799. return validhalign(a.halign) && validvalign(a.valign);
  3800. }
  3801. static int
  3802. validdimen(Dimen d)
  3803. {
  3804. int ok;
  3805. int s;
  3806. ok = 0;
  3807. s = d.kindspec&Dspecmask;
  3808. switch(d.kindspec&Dkindmask) {
  3809. case Dnone:
  3810. ok = s==0;
  3811. break;
  3812. case Dpixels:
  3813. ok = s < HUGEPIX;
  3814. break;
  3815. case Dpercent:
  3816. case Drelative:
  3817. ok = 1;
  3818. break;
  3819. }
  3820. return ok;
  3821. }
  3822. static int
  3823. validtablerow(Tablerow* r)
  3824. {
  3825. return (r->cells == nil || validptr(r->cells)) &&
  3826. (r->height >= 0 && r->height < HUGEPIX) &&
  3827. (r->ascent > -HUGEPIX && r->ascent < HUGEPIX) &&
  3828. validalign(r->align);
  3829. }
  3830. static int
  3831. validtablecol(Tablecol* c)
  3832. {
  3833. return c->width >= 0 && c->width < HUGEPIX
  3834. && validalign(c->align);
  3835. }
  3836. static int
  3837. validtablecell(Tablecell* c)
  3838. {
  3839. int ok;
  3840. ok = (c->next == nil || validptr(c->next)) &&
  3841. (c->nextinrow == nil || validptr(c->nextinrow)) &&
  3842. (c->content == nil || validptr(c->content)) &&
  3843. (c->lay == nil || validptr(c->lay)) &&
  3844. c->rowspan >= 0 &&
  3845. c->colspan >= 0 &&
  3846. validalign(c->align) &&
  3847. validdimen(c->wspec) &&
  3848. c->row >= 0 &&
  3849. c->col >= 0;
  3850. if(ok) {
  3851. if(c->content != nil)
  3852. ok = validitems(c->content);
  3853. }
  3854. return ok;
  3855. }
  3856. static int
  3857. validptr(void* p)
  3858. {
  3859. // TODO: a better job of this.
  3860. // For now, just dereference, which cause a bomb
  3861. // if not valid
  3862. static char c;
  3863. c = *((char*)p);
  3864. return 1;
  3865. }
  3866. static int
  3867. validStr(Rune* s)
  3868. {
  3869. return s != nil && validptr(s);
  3870. }