ms2html.c 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <ctype.h>
  4. #include <bio.h>
  5. enum
  6. {
  7. SSIZE = 10,
  8. Maxnh= 8, /* highest NH level */
  9. HH= 4, /* heading level used for SH and NH */
  10. Maxmstack= 10, /* deepest macro/string nesting */
  11. Narg= 20, /* max args to a macro */
  12. Maxsstack= 5, /* deepest nesting of .so's */
  13. Nline= 1024,
  14. Maxget= 10,
  15. Maxif = 20,
  16. Maxfsp = 100,
  17. /* list types */
  18. Lordered = 1,
  19. Lunordered,
  20. Ldef,
  21. Lother,
  22. };
  23. char *delim = "$$";
  24. char *basename;
  25. char *title;
  26. int eqnmode;
  27. int quiet;
  28. float indent; /* from .in */
  29. Biobuf bout;
  30. int isup;
  31. int isdown;
  32. int debug;
  33. int nh[Maxnh];
  34. int ifwastrue[Maxif];
  35. int list, listnum, example;
  36. int hangingau, hangingdt, hanginghead, hangingcenter;
  37. int indirective, paragraph, sol, titleseen, ignore_nl, weBref;
  38. void dohangingcenter(void);
  39. typedef struct Goobie Goobie;
  40. typedef struct Goobieif Goobieif;
  41. struct Goobie
  42. {
  43. char *name;
  44. void (*f)(int, char**);
  45. };
  46. typedef void F(int, char**);
  47. typedef void Fif(char*, char*);
  48. struct Goobieif
  49. {
  50. char *name;
  51. Fif *f;
  52. };
  53. /* if, ie */
  54. Fif g_as, g_ds, g_el, g_ie, g_if;
  55. Goobieif gtabif[] = {
  56. { "as", g_as },
  57. { "ds", g_ds },
  58. { "if", g_if },
  59. { "ie", g_ie },
  60. { "el", g_el },
  61. { nil, nil },
  62. };
  63. /* pseudo ops */
  64. F g_notyet, g_ignore, g_hrule, g_startgif;
  65. /* ms macros */
  66. F g_AU, g_B, g_BI, g_CW, g_I, g_IP, g_LP, g_PP, g_SH, g_NH;
  67. F g_P1, g_P2, g_TL, g_R, g_AB, g_AE, g_EQ, g_TS, g_TE, g_FS, g_FE;
  68. F g_PY, g_IH, g_MH, g_HO, g_BX, g_QS, g_QE, g_RS, g_RE;
  69. /* pictures macro */
  70. F g_BP;
  71. /* real troff */
  72. F g_br, g_ft, g_sp, g_de, g_lf, g_so, g_rm, g_in;
  73. F g_nr, g_ig, g_RT, g_BS, g_BE, g_LB, g_ta;
  74. /* macros to include ML in output */
  75. F g__H, g__T;
  76. Goobie gtab[] =
  77. {
  78. { "_T", g__T, },
  79. { "_H", g__H, },
  80. { "1C", g_ignore, },
  81. { "2C", g_ignore, },
  82. { "AB", g_AB, },
  83. { "AE", g_AE, },
  84. { "AI", g_ignore, },
  85. { "AU", g_AU, },
  86. { "B", g_B, },
  87. { "B1", g_hrule, },
  88. { "B2", g_hrule, },
  89. { "BI", g_BI, },
  90. { "BP", g_BP, },
  91. { "BT", g_ignore, },
  92. { "BX", g_BX, },
  93. { "CW", g_CW, },
  94. { "CT", g_ignore, },
  95. { "DA", g_ignore, },
  96. { "DE", g_P2, },
  97. { "DS", g_P1, },
  98. { "EG", g_ignore, },
  99. { "EN", g_ignore, },
  100. { "EQ", g_startgif, },
  101. { "FE", g_FE, },
  102. { "FP", g_ignore, },
  103. { "FS", g_FS, },
  104. { "HO", g_HO, },
  105. { "I", g_I, },
  106. { "IH", g_IH, },
  107. { "IM", g_ignore, },
  108. { "IP", g_IP, },
  109. { "KE", g_ignore, },
  110. { "KF", g_ignore, },
  111. { "KS", g_ignore, },
  112. { "LG", g_ignore, },
  113. { "LP", g_LP, },
  114. { "LT", g_ignore, },
  115. { "MF", g_ignore, },
  116. { "MH", g_MH, },
  117. { "MR", g_ignore, },
  118. { "ND", g_ignore, },
  119. { "NH", g_NH, },
  120. { "NL", g_ignore, },
  121. { "P1", g_P1, },
  122. { "P2", g_P2, },
  123. { "PE", g_ignore, },
  124. { "PF", g_ignore, },
  125. { "PP", g_PP, },
  126. { "PS", g_startgif, },
  127. { "PY", g_PY, },
  128. { "QE", g_QE, },
  129. { "QP", g_QS, },
  130. { "QS", g_QS, },
  131. { "R", g_R, },
  132. { "RE", g_RE, },
  133. { "RP", g_ignore, },
  134. { "RS", g_RS, },
  135. { "SG", g_ignore, },
  136. { "SH", g_SH, },
  137. { "SM", g_ignore, },
  138. { "TA", g_ignore, },
  139. { "TE", g_ignore, },
  140. { "TH", g_TL, },
  141. { "TL", g_TL, },
  142. { "TM", g_ignore, },
  143. { "TR", g_ignore, },
  144. { "TS", g_startgif, },
  145. { "UL", g_I, },
  146. { "UX", g_ignore, },
  147. { "WH", g_ignore, },
  148. { "RT", g_RT, },
  149. { "br", g_br, },
  150. { "ti", g_br, },
  151. { "nf", g_P1, },
  152. { "fi", g_P2, },
  153. { "ft", g_ft, },
  154. { "sp", g_sp, },
  155. { "rm", g_rm, },
  156. { "de", g_de, },
  157. { "am", g_de, },
  158. { "lf", g_lf, },
  159. { "so", g_so, },
  160. { "ps", g_ignore },
  161. { "vs", g_ignore },
  162. { "nr", g_nr },
  163. { "in", g_in },
  164. { "ne", g_ignore },
  165. { "ig", g_ig },
  166. { "BS", g_BS },
  167. { "BE", g_BE },
  168. { "LB", g_LB },
  169. { nil, nil },
  170. };
  171. typedef struct Entity Entity;
  172. struct Entity
  173. {
  174. char *name;
  175. int value;
  176. };
  177. Entity entity[] =
  178. {
  179. { "&#SPACE;", L' ', },
  180. { "&#RS;", L'\n', },
  181. { "&#RE;", L'\r', },
  182. { "&quot;", L'"', },
  183. { "&AElig;", L'Æ', },
  184. { "&Aacute;", L'Á', },
  185. { "&Acirc;", L'Â', },
  186. { "&Agrave;", L'À', },
  187. { "&Aring;", L'Å', },
  188. { "&Atilde;", L'Ã', },
  189. { "&Auml;", L'Ä', },
  190. { "&Ccedil;", L'Ç', },
  191. { "&ETH;", L'Ð', },
  192. { "&Eacute;", L'É', },
  193. { "&Ecirc;", L'Ê', },
  194. { "&Egrave;", L'È', },
  195. { "&Euml;", L'Ë', },
  196. { "&Iacute;", L'Í', },
  197. { "&Icirc;", L'Î', },
  198. { "&Igrave;", L'Ì', },
  199. { "&Iuml;", L'Ï', },
  200. { "&Ntilde;", L'Ñ', },
  201. { "&Oacute;", L'Ó', },
  202. { "&Ocirc;", L'Ô', },
  203. { "&Ograve;", L'Ò', },
  204. { "&Oslash;", L'Ø', },
  205. { "&Otilde;", L'Õ', },
  206. { "&Ouml;", L'Ö', },
  207. { "&THORN;", L'Þ', },
  208. { "&Uacute;", L'Ú', },
  209. { "&Ucirc;", L'Û', },
  210. { "&Ugrave;", L'Ù', },
  211. { "&Uuml;", L'Ü', },
  212. { "&Yacute;", L'Ý', },
  213. { "&aacute;", L'á', },
  214. { "&acirc;", L'â', },
  215. { "&aelig;", L'æ', },
  216. { "&agrave;", L'à', },
  217. { "&amp;", L'&', },
  218. { "&aring;", L'å', },
  219. { "&atilde;", L'ã', },
  220. { "&auml;", L'ä', },
  221. { "&ccedil;", L'ç', },
  222. { "&eacute;", L'é', },
  223. { "&ecirc;", L'ê', },
  224. { "&egrave;", L'è', },
  225. { "&eth;", L'ð', },
  226. { "&euml;", L'ë', },
  227. { "&gt;", L'>', },
  228. { "&iacute;", L'í', },
  229. { "&icirc;", L'î', },
  230. { "&igrave;", L'ì', },
  231. { "&iuml;", L'ï', },
  232. { "&lt;", L'<', },
  233. { "&ntilde;", L'ñ', },
  234. { "&oacute;", L'ó', },
  235. { "&ocirc;", L'ô', },
  236. { "&ograve;", L'ò', },
  237. { "&oslash;", L'ø', },
  238. { "&otilde;", L'õ', },
  239. { "&ouml;", L'ö', },
  240. { "&szlig;", L'ß', },
  241. { "&thorn;", L'þ', },
  242. { "&uacute;", L'ú', },
  243. { "&ucirc;", L'û', },
  244. { "&ugrave;", L'ù', },
  245. { "&uuml;", L'ü', },
  246. { "&yacute;", L'ý', },
  247. { "&yuml;", L'ÿ', },
  248. { "&#161;", L'¡', },
  249. { "&#162;", L'¢', },
  250. { "&#163;", L'£', },
  251. { "&#164;", L'¤', },
  252. { "&#165;", L'¥', },
  253. { "&#166;", L'¦', },
  254. { "&#167;", L'§', },
  255. { "&#168;", L'¨', },
  256. { "&#169;", L'©', },
  257. { "&#170;", L'ª', },
  258. { "&#171;", L'«', },
  259. { "&#172;", L'¬', },
  260. { "&#173;", L'­', },
  261. { "&#174;", L'®', },
  262. { "&#175;", L'¯', },
  263. { "&#176;", L'°', },
  264. { "&#177;", L'±', },
  265. { "&#178;", L'²', },
  266. { "&#179;", L'³', },
  267. { "&#180;", L'´', },
  268. { "&#181;", L'µ', },
  269. { "&#182;", L'¶', },
  270. { "&#183;", L'·', },
  271. { "&#184;", L'¸', },
  272. { "&#185;", L'¹', },
  273. { "&#186;", L'º', },
  274. { "&#187;", L'»', },
  275. { "&#188;", L'¼', },
  276. { "&#189;", L'½', },
  277. { "&#190;", L'¾', },
  278. { "&#191;", L'¿', },
  279. { "*", L'•', },
  280. { "&#164;", L'□', },
  281. { "&#186;", L'◊', },
  282. { "(tm)", L'™', },
  283. {"&#913;", L'Α',},
  284. {"&#914;", L'Β',},
  285. {"&#915;", L'Γ',},
  286. {"&#916;", L'Δ',},
  287. {"&#917;", L'Ε',},
  288. {"&#918;", L'Ζ',},
  289. {"&#919;", L'Η',},
  290. {"&#920;", L'Θ',},
  291. {"&#921;", L'Ι',},
  292. {"&#922;", L'Κ',},
  293. {"&#923;", L'Λ',},
  294. {"&#924;", L'Μ',},
  295. {"&#925;", L'Ν',},
  296. {"&#926;", L'Ξ',},
  297. {"&#927;", L'Ο',},
  298. {"&#928;", L'Π',},
  299. {"&#929;", L'Ρ',},
  300. {"&#930;", L'΢',},
  301. {"&#931;", L'Σ',},
  302. {"&#932;", L'Τ',},
  303. {"&#933;", L'Υ',},
  304. {"&#934;", L'Φ',},
  305. {"&#935;", L'Χ',},
  306. {"&#936;", L'Ψ',},
  307. {"&#937;", L'Ω',},
  308. {"&#945;", L'α',},
  309. {"&#946;", L'β',},
  310. {"&#947;", L'γ',},
  311. {"&#948;", L'δ',},
  312. {"&#949;", L'ε',},
  313. {"&#950;", L'ζ',},
  314. {"&#951;", L'η',},
  315. {"&#952;", L'θ',},
  316. {"&#953;", L'ι',},
  317. {"&#954;", L'κ',},
  318. {"&#955;", L'λ',},
  319. {"&#956;", L'μ',},
  320. {"&#957;", L'ν',},
  321. {"&#958;", L'ξ',},
  322. {"&#959;", L'ο',},
  323. {"&#960;", L'π',},
  324. {"&#961;", L'ρ',},
  325. {"&#962;", L'ς',},
  326. {"&#963;", L'σ',},
  327. {"&#964;", L'τ',},
  328. {"&#965;", L'υ',},
  329. {"&#966;", L'φ',},
  330. {"&#967;", L'χ',},
  331. {"&#968;", L'ψ',},
  332. {"&#969;", L'ω',},
  333. { "<-", L'←', },
  334. { "^", L'↑', },
  335. { "->", L'→', },
  336. { "v", L'↓', },
  337. { "!=", L'≠', },
  338. { "<=", L'≤', },
  339. { "...", L'⋯', },
  340. {"&isin;", L'∈', },
  341. {"&#8211;", L'–', },
  342. {"&#8212;", L'—', },
  343. { "CYRILLIC XYZZY", L'й', },
  344. { "CYRILLIC XYZZY", L'ъ', },
  345. { "CYRILLIC Y", L'ь', },
  346. { "CYRILLIC YA", L'я', },
  347. { "CYRILLIC YA", L'ё', },
  348. { "&#191;", L'ℱ', },
  349. { nil, 0 },
  350. };
  351. typedef struct Troffspec Troffspec;
  352. struct Troffspec
  353. {
  354. char *name;
  355. char *value;
  356. };
  357. Troffspec tspec[] =
  358. {
  359. { "A*", "&Aring;", },
  360. { "o\"", "&ouml;", },
  361. { "ff", "ff", },
  362. { "fi", "fi", },
  363. { "fl", "fl", },
  364. { "Fi", "ffi", },
  365. { "ru", "_", },
  366. { "em", "&#173;", },
  367. { "14", "&#188;", },
  368. { "12", "&#189;", },
  369. { "co", "&#169;", },
  370. { "de", "&#176;", },
  371. { "dg", "&#161;", },
  372. { "fm", "&#180;", },
  373. { "rg", "&#174;", },
  374. { "bu", "*", },
  375. { "sq", "&#164;", },
  376. { "hy", "-", },
  377. { "pl", "+", },
  378. { "mi", "-", },
  379. { "mu", "&#215;", },
  380. { "di", "&#247;", },
  381. { "eq", "=", },
  382. { "==", "==", },
  383. { ">=", ">=", },
  384. { "<=", "<=", },
  385. { "!=", "!=", },
  386. { "+-", "&#177;", },
  387. { "no", "&#172;", },
  388. { "sl", "/", },
  389. { "ap", "&", },
  390. { "~=", "~=", },
  391. { "pt", "oc", },
  392. { "gr", "GRAD", },
  393. { "->", "->", },
  394. { "<-", "<-", },
  395. { "ua", "^", },
  396. { "da", "v", },
  397. { "is", "Integral", },
  398. { "pd", "DIV", },
  399. { "if", "oo", },
  400. { "sr", "-/", },
  401. { "sb", "(~", },
  402. { "sp", "~)", },
  403. { "cu", "U", },
  404. { "ca", "(^)", },
  405. { "ib", "(=", },
  406. { "ip", "=)", },
  407. { "mo", "C", },
  408. { "es", "&Oslash;", },
  409. { "aa", "&#180;", },
  410. { "ga", "`", },
  411. { "ci", "O", },
  412. { "L1", "DEATHSTAR", },
  413. { "sc", "&#167;", },
  414. { "dd", "++", },
  415. { "lh", "<=", },
  416. { "rh", "=>", },
  417. { "lt", "(", },
  418. { "rt", ")", },
  419. { "lc", "|", },
  420. { "rc", "|", },
  421. { "lb", "(", },
  422. { "rb", ")", },
  423. { "lf", "|", },
  424. { "rf", "|", },
  425. { "lk", "|", },
  426. { "rk", "|", },
  427. { "bv", "|", },
  428. { "ts", "s", },
  429. { "br", "|", },
  430. { "or", "|", },
  431. { "ul", "_", },
  432. { "rn", " ", },
  433. { "**", "*", },
  434. { "tm", "&#153", },
  435. { nil, nil, },
  436. };
  437. typedef struct Font Font;
  438. struct Font
  439. {
  440. char *start;
  441. char *end;
  442. };
  443. Font bfont = { "<B>", "</B>" };
  444. Font ifont = { "<I>", "</I>" };
  445. Font bifont = { "<B><I>", "</I></B>" };
  446. Font cwfont = { "<TT>", "</TT>" };
  447. Font *fstack[Maxfsp];
  448. int fsp = -1;
  449. typedef struct String String;
  450. struct String
  451. {
  452. String *next;
  453. char *name;
  454. char *val;
  455. };
  456. String *numregs, *strings;
  457. char *strstack[Maxmstack];
  458. char *mustfree[Maxmstack];
  459. int strsp = -1;
  460. int elsetop = -1;
  461. typedef struct Mstack Mstack;
  462. struct Mstack
  463. {
  464. char *ptr;
  465. char *argv[Narg+1];
  466. };
  467. String *macros;
  468. Mstack mstack[Maxmstack];
  469. int msp = -1;
  470. typedef struct Srcstack Srcstack;
  471. struct Srcstack
  472. {
  473. char filename[256];
  474. int fd;
  475. int lno;
  476. int rlno;
  477. Biobuf in;
  478. };
  479. Srcstack sstack[Maxsstack];
  480. Srcstack *ssp = &sstack[-1];
  481. char token[128];
  482. void closel(void);
  483. void closefont(void);
  484. void*
  485. emalloc(uint n)
  486. {
  487. void *p;
  488. p = mallocz(n, 1);
  489. if(p == nil){
  490. fprint(2, "ms2html: malloc failed: %r\n");
  491. exits("malloc");
  492. }
  493. return p;
  494. }
  495. /* define a string variable */
  496. void
  497. dsnr(char *name, char *val, String **l)
  498. {
  499. String *s;
  500. for(s = *l; s != nil; s = *l){
  501. if(strcmp(s->name, name) == 0)
  502. break;
  503. l = &s->next;
  504. }
  505. if(s == nil){
  506. s = emalloc(sizeof(String));
  507. *l = s;
  508. s->name = strdup(name);
  509. } else
  510. free(s->val);
  511. s->val = strdup(val);
  512. }
  513. void
  514. ds(char *name, char *val)
  515. {
  516. dsnr(name, val, &strings);
  517. }
  518. /* look up a defined string */
  519. char*
  520. getds(char *name)
  521. {
  522. String *s;
  523. for(s = strings; s != nil; s = s->next)
  524. if(strcmp(name, s->name) == 0)
  525. break;
  526. if(s != nil)
  527. return s->val;
  528. return "";
  529. }
  530. char *
  531. getnr(char *name)
  532. {
  533. String *s;
  534. for(s = numregs; s != nil; s = s->next)
  535. if(strcmp(name, s->name) == 0)
  536. break;
  537. if(s != nil)
  538. return s->val;
  539. return "0";
  540. }
  541. void
  542. pushstr(char *p)
  543. {
  544. if(p == nil)
  545. return;
  546. if(strsp >= Maxmstack - 1)
  547. return;
  548. strstack[++strsp] = p;
  549. }
  550. /* lookup a defined macro */
  551. char*
  552. getmacro(char *name)
  553. {
  554. String *s;
  555. for(s = macros; s != nil; s = s->next)
  556. if(strcmp(name, s->name) == 0)
  557. return s->val;
  558. return nil;
  559. }
  560. enum
  561. {
  562. Dstring,
  563. Macro,
  564. Input,
  565. };
  566. int lastsrc;
  567. void
  568. pushsrc(char *name)
  569. {
  570. Dir *d;
  571. int fd;
  572. if(ssp == &sstack[Maxsstack-1]){
  573. fprint(2, "ms2html: .so's too deep\n");
  574. return;
  575. }
  576. d = nil;
  577. if(name == nil){
  578. d = dirfstat(0);
  579. if(d == nil){
  580. fprint(2, "ms2html: can't stat %s: %r\n", name);
  581. return;
  582. }
  583. name = d->name;
  584. fd = 0;
  585. } else {
  586. fd = open(name, OREAD);
  587. if(fd < 0){
  588. fprint(2, "ms2html: can't open %s: %r\n", name);
  589. return;
  590. }
  591. }
  592. ssp++;
  593. ssp->fd = fd;
  594. Binit(&ssp->in, fd, OREAD);
  595. snprint(ssp->filename, sizeof(ssp->filename), "%s", name);
  596. ssp->lno = ssp->rlno = 1;
  597. free(d);
  598. }
  599. /* get next logical byte. from stdin or a defined string */
  600. int
  601. getrune(void)
  602. {
  603. int i;
  604. Rune r;
  605. int c;
  606. Mstack *m;
  607. while(strsp >= 0){
  608. i = chartorune(&r, strstack[strsp]);
  609. if(r != 0){
  610. strstack[strsp] += i;
  611. lastsrc = Dstring;
  612. return r;
  613. }
  614. if (mustfree[strsp]) {
  615. free(mustfree[strsp]);
  616. mustfree[strsp] = nil;
  617. }
  618. strsp--;
  619. }
  620. while(msp >= 0){
  621. m = &mstack[msp];
  622. i = chartorune(&r, m->ptr);
  623. if(r != 0){
  624. m->ptr += i;
  625. lastsrc = Macro;
  626. return r;
  627. }
  628. for(i = 0; m->argv[i] != nil; i++)
  629. free(m->argv[i]);
  630. msp--;
  631. }
  632. lastsrc = Input;
  633. for(;;) {
  634. if(ssp < sstack)
  635. return -1;
  636. c = Bgetrune(&ssp->in);
  637. if(c >= 0){
  638. r = c;
  639. break;
  640. }
  641. close(ssp->fd);
  642. ssp--;
  643. }
  644. return r;
  645. }
  646. void
  647. ungetrune(void)
  648. {
  649. switch(lastsrc){
  650. case Dstring:
  651. if(strsp >= 0)
  652. strstack[strsp]--;
  653. break;
  654. case Macro:
  655. if(msp >= 0)
  656. mstack[msp].ptr--;
  657. break;
  658. case Input:
  659. if(ssp >= sstack)
  660. Bungetrune(&ssp->in);
  661. break;
  662. }
  663. }
  664. int vert;
  665. char*
  666. changefont(Font *f)
  667. {
  668. token[0] = 0;
  669. if(fsp == Maxfsp)
  670. return token;
  671. if(fsp >= 0 && fstack[fsp])
  672. strcpy(token, fstack[fsp]->end);
  673. if(f != nil)
  674. strcat(token, f->start);
  675. fstack[++fsp] = f;
  676. return token;
  677. }
  678. char*
  679. changebackfont(void)
  680. {
  681. token[0] = 0;
  682. if(fsp >= 0){
  683. if(fstack[fsp])
  684. strcpy(token, fstack[fsp]->end);
  685. fsp--;
  686. }
  687. if(fsp >= 0 && fstack[fsp])
  688. strcat(token, fstack[fsp]->start);
  689. return token;
  690. }
  691. char*
  692. changesize(int amount)
  693. {
  694. static int curamount;
  695. static char buf[200];
  696. int i;
  697. buf[0] = 0;
  698. if (curamount >= 0)
  699. for (i = 0; i < curamount; i++)
  700. strcat(buf, "</big>");
  701. else
  702. for (i = 0; i < -curamount; i++)
  703. strcat(buf, "</small>");
  704. curamount = 0;
  705. if (amount >= 0)
  706. for (i = 0; i < amount; i++)
  707. strcat(buf, "<big>");
  708. else
  709. for (i = 0; i < -amount; i++)
  710. strcat(buf, "<small>");
  711. curamount = amount;
  712. return buf;
  713. }
  714. /* get next logical character. expand it with escapes */
  715. char*
  716. getnext(void)
  717. {
  718. int r;
  719. Entity *e;
  720. Troffspec *t;
  721. Rune R;
  722. char str[4];
  723. static char buf[8];
  724. r = getrune();
  725. if(r < 0)
  726. return nil;
  727. if(r > 128 || r == '<' || r == '>'){
  728. for(e = entity; e->name; e++)
  729. if(e->value == r)
  730. return e->name;
  731. sprint(buf, "&#%d;", r);
  732. return buf;
  733. }
  734. if (r == delim[eqnmode]){
  735. if (eqnmode == 0){
  736. eqnmode = 1;
  737. return changefont(&ifont);
  738. }
  739. eqnmode = 0;
  740. return changebackfont();
  741. }
  742. switch(r){
  743. case '\\':
  744. r = getrune();
  745. if(r < 0)
  746. return nil;
  747. switch(r){
  748. case ' ':
  749. return " ";
  750. /* chars to ignore */
  751. case '&':
  752. case '|':
  753. case '%':
  754. return "";
  755. /* small space in troff, nothing in nroff */
  756. case '^':
  757. return getnext();
  758. /* ignore arg */
  759. case 'k':
  760. getrune();
  761. return getnext();
  762. /* comment */
  763. case '"':
  764. while(getrune() != '\n')
  765. ;
  766. return "\n";
  767. /* ignore line */
  768. case '!':
  769. while(getrune() != '\n')
  770. ;
  771. ungetrune();
  772. return getnext();
  773. /* defined strings */
  774. case '*':
  775. r = getrune();
  776. if(r == '('){
  777. str[0] = getrune();
  778. str[1] = getrune();
  779. str[2] = 0;
  780. } else {
  781. str[0] = r;
  782. str[1] = 0;
  783. }
  784. pushstr(getds(str));
  785. return getnext();
  786. /* macro args */
  787. case '$':
  788. r = getrune();
  789. if(r < '1' || r > '9'){
  790. token[0] = '\\';
  791. token[1] = '$';
  792. token[2] = r;
  793. token[3] = 0;
  794. return token;
  795. }
  796. r -= '0';
  797. if(msp >= 0)
  798. pushstr(mstack[msp].argv[r]);
  799. return getnext();
  800. /* special chars */
  801. case '(':
  802. token[0] = getrune();
  803. token[1] = getrune();
  804. token[2] = 0;
  805. for(t = tspec; t->name; t++)
  806. if(strcmp(token, t->name) == 0)
  807. return t->value;
  808. return "&#191;";
  809. /* ignore immediately following newline */
  810. case 'c':
  811. r = getrune();
  812. if (r == '\n') {
  813. sol = ignore_nl = 1;
  814. if (indirective)
  815. break;
  816. }
  817. else
  818. ungetrune();
  819. return getnext();
  820. /* escape backslash */
  821. case 'e':
  822. return "\\";
  823. /* font change */
  824. case 'f':
  825. r = getrune();
  826. switch(r){
  827. case '(':
  828. str[0] = getrune();
  829. str[1] = getrune();
  830. str[2] = 0;
  831. token[0] = 0;
  832. if(strcmp("BI", str) == 0)
  833. return changefont(&bifont);
  834. else if(strcmp("CW", str) == 0)
  835. return changefont(&cwfont);
  836. else
  837. return changefont(nil);
  838. case '3':
  839. case 'B':
  840. return changefont(&bfont);
  841. case '2':
  842. case 'I':
  843. return changefont(&ifont);
  844. case '4':
  845. return changefont(&bifont);
  846. case '5':
  847. return changefont(&cwfont);
  848. case 'P':
  849. return changebackfont();
  850. case 'R':
  851. default:
  852. return changefont(nil);
  853. }
  854. /* number register */
  855. case 'n':
  856. r = getrune();
  857. if (r == '(') /*)*/ {
  858. r = getrune();
  859. if (r < 0)
  860. return nil;
  861. str[0] = r;
  862. r = getrune();
  863. if (r < 0)
  864. return nil;
  865. str[1] = r;
  866. str[2] = 0;
  867. }
  868. else {
  869. str[0] = r;
  870. str[1] = 0;
  871. }
  872. pushstr(getnr(str));
  873. return getnext();
  874. /* font size */
  875. case 's':
  876. r = getrune();
  877. switch(r){
  878. case '0':
  879. return changesize(0);
  880. case '-':
  881. r = getrune();
  882. if (!isdigit(r))
  883. return getnext();
  884. return changesize(-(r - '0'));
  885. case '+':
  886. r = getrune();
  887. if (!isdigit(r))
  888. return getnext();
  889. return changesize(r - '0');
  890. }
  891. return getnext();
  892. /* vertical movement */
  893. case 'v':
  894. r = getrune();
  895. if(r != '\''){
  896. ungetrune();
  897. return getnext();
  898. }
  899. r = getrune();
  900. if(r != '-')
  901. vert--;
  902. else
  903. vert++;
  904. while(r != '\'' && r != '\n')
  905. r = getrune();
  906. if(r != '\'')
  907. ungetrune();
  908. if(vert > 0)
  909. return "^";
  910. return getnext();
  911. /* horizontal line */
  912. case 'l':
  913. r = getrune();
  914. if(r != '\''){
  915. ungetrune();
  916. return "<HR>";
  917. }
  918. while(getrune() != '\'')
  919. ;
  920. return "<HR>";
  921. /* character height and slant */
  922. case 'S':
  923. case 'H':
  924. r = getrune();
  925. if(r != '\''){
  926. ungetrune();
  927. return "<HR>";
  928. }
  929. while(getrune() != '\'')
  930. ;
  931. return getnext();
  932. /* digit-width space */
  933. case '0':
  934. return " ";
  935. /*for .if, .ie, .el */
  936. case '{':
  937. return "\\{"; /*}*/
  938. case '}':
  939. return "";
  940. /* up and down */
  941. case 'u':
  942. if (isdown) {
  943. isdown = 0;
  944. return "</sub>";
  945. }
  946. isup = 1;
  947. return "<sup>";
  948. case 'd':
  949. if (isup) {
  950. isup = 0;
  951. return "</sup>";
  952. }
  953. isdown = 1;
  954. return "<sub>";
  955. }
  956. break;
  957. case '&':
  958. if(msp >= 0 || strsp >= 0)
  959. return "&";
  960. return "&amp;";
  961. case '<':
  962. if(msp >= 0 || strsp >= 0)
  963. return "<";
  964. return "&#60;";
  965. case '>':
  966. if(msp >= 0 || strsp >= 0)
  967. return ">";
  968. return "&#62;";
  969. }
  970. if (r < Runeself) {
  971. token[0] = r;
  972. token[1] = 0;
  973. }
  974. else {
  975. R = r;
  976. token[runetochar(token,&R)] = 0;
  977. }
  978. return token;
  979. }
  980. /* if arg0 is set, read up to (and expand) to the next whitespace, else to the end of line */
  981. char*
  982. copyline(char *p, char *e, int arg0)
  983. {
  984. int c;
  985. Rune r;
  986. char *p1;
  987. while((c = getrune()) == ' ' || c == '\t')
  988. ;
  989. for(indirective = 1; p < e; c = getrune()) {
  990. if (c < 0)
  991. goto done;
  992. switch(c) {
  993. case '\\':
  994. break;
  995. case '\n':
  996. if (arg0)
  997. ungetrune();
  998. goto done;
  999. case ' ':
  1000. case '\t':
  1001. if (arg0)
  1002. goto done;
  1003. default:
  1004. r = c;
  1005. p += runetochar(p,&r);
  1006. continue;
  1007. }
  1008. ungetrune();
  1009. p1 = getnext();
  1010. if (p1 == nil)
  1011. goto done;
  1012. if (*p1 == '\n') {
  1013. if (arg0)
  1014. ungetrune();
  1015. break;
  1016. }
  1017. while((*p = *p1++) && p < e)
  1018. p++;
  1019. }
  1020. done:
  1021. indirective = 0;
  1022. *p++ = 0;
  1023. return p;
  1024. }
  1025. char*
  1026. copyarg(char *p, char *e, int *nullarg)
  1027. {
  1028. int c, quoted, last;
  1029. Rune r;
  1030. *nullarg = 0;
  1031. quoted = 0;
  1032. do{
  1033. c = getrune();
  1034. } while(c == ' ' || c == '\t');
  1035. if(c == '"'){
  1036. quoted = 1;
  1037. *nullarg = 1;
  1038. c = getrune();
  1039. }
  1040. if(c == '\n')
  1041. goto done;
  1042. last = 0;
  1043. for(; p < e; c = getrune()) {
  1044. if (c < 0)
  1045. break;
  1046. switch(c) {
  1047. case '\n':
  1048. ungetrune();
  1049. goto done;
  1050. case '\\':
  1051. r = c;
  1052. p += runetochar(p,&r);
  1053. if(last == '\\')
  1054. r = 0;
  1055. break;
  1056. case ' ':
  1057. case '\t':
  1058. if(!quoted && last != '\\')
  1059. goto done;
  1060. r = c;
  1061. p += runetochar(p,&r);
  1062. break;
  1063. case '"':
  1064. if(quoted && last != '\\')
  1065. goto done;
  1066. r = c;
  1067. p += runetochar(p,&r);
  1068. break;
  1069. default:
  1070. r = c;
  1071. p += runetochar(p,&r);
  1072. break;
  1073. }
  1074. last = r;
  1075. }
  1076. done:
  1077. *p++ = 0;
  1078. return p;
  1079. }
  1080. int
  1081. parseargs(char *p, char *e, char **argv)
  1082. {
  1083. int argc;
  1084. char *np;
  1085. int nullarg;
  1086. indirective = 1;
  1087. *p++ = 0;
  1088. for(argc = 1; argc < Narg; argc++){
  1089. np = copyarg(p, e, &nullarg);
  1090. if(nullarg==0 && np == p+1)
  1091. break;
  1092. argv[argc] = p;
  1093. p = np;
  1094. }
  1095. argv[argc] = nil;
  1096. indirective = 0;
  1097. return argc;
  1098. }
  1099. void
  1100. dodirective(void)
  1101. {
  1102. char *p, *e;
  1103. Goobie *g;
  1104. Goobieif *gif;
  1105. char line[Nline], *line1;
  1106. int i, argc;
  1107. char *argv[Narg];
  1108. Mstack *m;
  1109. /* read line, translate special bytes */
  1110. e = line + sizeof(line) - UTFmax - 1;
  1111. line1 = copyline(line, e, 1);
  1112. if (!line[0])
  1113. return;
  1114. argv[0] = line;
  1115. /* first look through user defined macros */
  1116. p = getmacro(argv[0]);
  1117. if(p != nil){
  1118. if(msp == Maxmstack-1){
  1119. fprint(2, "ms2html: macro stack overflow\n");
  1120. return;
  1121. }
  1122. argc = parseargs(line1, e, argv);
  1123. m = &mstack[++msp];
  1124. m->ptr = p;
  1125. memset(m->argv, 0, sizeof(m->argv));
  1126. for(i = 0; i < argc; i++)
  1127. m->argv[i] = strdup(argv[i]);
  1128. return;
  1129. }
  1130. /* check for .if or .ie */
  1131. for(gif = gtabif; gif->name; gif++)
  1132. if(strcmp(gif->name, argv[0]) == 0){
  1133. (*gif->f)(line1, e);
  1134. return;
  1135. }
  1136. argc = parseargs(line1, e, argv);
  1137. /* try standard ms macros */
  1138. for(g = gtab; g->name; g++)
  1139. if(strcmp(g->name, argv[0]) == 0){
  1140. (*g->f)(argc, argv);
  1141. return;
  1142. }
  1143. if(debug)
  1144. fprint(2, "stdin %d(%s:%d): unknown directive %s\n",
  1145. ssp->lno, ssp->filename, ssp->rlno, line);
  1146. }
  1147. void
  1148. printarg(char *a)
  1149. {
  1150. char *e, *p;
  1151. e = a + strlen(a);
  1152. pushstr(a);
  1153. while(strsp >= 0 && strstack[strsp] >= a && strstack[strsp] < e){
  1154. p = getnext();
  1155. if(p == nil)
  1156. return;
  1157. Bprint(&bout, "%s", p);
  1158. }
  1159. }
  1160. void
  1161. printargs(int argc, char **argv)
  1162. {
  1163. argc--;
  1164. argv++;
  1165. while(--argc > 0){
  1166. printarg(*argv++);
  1167. Bprint(&bout, " ");
  1168. }
  1169. if(argc == 0)
  1170. printarg(*argv);
  1171. }
  1172. void
  1173. dohangingdt(void)
  1174. {
  1175. switch(hangingdt){
  1176. case 3:
  1177. hangingdt--;
  1178. break;
  1179. case 2:
  1180. Bprint(&bout, "<dd>");
  1181. hangingdt = 0;
  1182. break;
  1183. }
  1184. }
  1185. void
  1186. dohangingau(void)
  1187. {
  1188. if(hangingau == 0)
  1189. return;
  1190. Bprint(&bout, "</I></DL>\n");
  1191. hangingau = 0;
  1192. }
  1193. void
  1194. dohanginghead(void)
  1195. {
  1196. if(hanginghead == 0)
  1197. return;
  1198. Bprint(&bout, "</H%d>\n", hanginghead);
  1199. hanginghead = 0;
  1200. }
  1201. /*
  1202. * convert a man page to html and output
  1203. */
  1204. void
  1205. doconvert(void)
  1206. {
  1207. char c, *p;
  1208. Tm *t;
  1209. pushsrc(nil);
  1210. sol = 1;
  1211. Bprint(&bout, "<html>\n");
  1212. Bflush(&bout);
  1213. for(;;){
  1214. p = getnext();
  1215. if(p == nil)
  1216. break;
  1217. c = *p;
  1218. if(c == '.' && sol){
  1219. dodirective();
  1220. dohangingdt();
  1221. ssp->lno++;
  1222. ssp->rlno++;
  1223. sol = 1;
  1224. } else if(c == '\n'){
  1225. if (ignore_nl)
  1226. ignore_nl = 0;
  1227. else {
  1228. if(hangingau)
  1229. Bprint(&bout, "<br>\n");
  1230. else
  1231. Bprint(&bout, "%s", p);
  1232. dohangingdt();
  1233. }
  1234. ssp->lno++;
  1235. ssp->rlno++;
  1236. sol = 1;
  1237. } else{
  1238. Bprint(&bout, "%s", p);
  1239. ignore_nl = sol = 0;
  1240. }
  1241. }
  1242. dohanginghead();
  1243. dohangingdt();
  1244. closel();
  1245. if(fsp >= 0 && fstack[fsp])
  1246. Bprint(&bout, "%s", fstack[fsp]->end);
  1247. Bprint(&bout, "<br>&#32;<br>\n");
  1248. Bprint(&bout, "<A href=http://www.lucent.com/copyright.html>\n");
  1249. t = localtime(time(nil));
  1250. Bprint(&bout, "Copyright</A> &#169; %d Lucent Technologies Inc. All rights reserved.\n",
  1251. t->year+1900);
  1252. Bprint(&bout, "</body></html>\n");
  1253. }
  1254. static void
  1255. usage(void)
  1256. {
  1257. sysfatal("usage: ms2html [-q] [-b basename] [-d '$$'] [-t title]\n");
  1258. }
  1259. void
  1260. main(int argc, char **argv)
  1261. {
  1262. quiet = 1;
  1263. ARGBEGIN {
  1264. case 't':
  1265. title = EARGF(usage());
  1266. break;
  1267. case 'b':
  1268. basename = EARGF(usage());
  1269. break;
  1270. case 'q':
  1271. quiet = 0;
  1272. break;
  1273. case 'd':
  1274. delim = EARGF(usage());
  1275. break;
  1276. case '?':
  1277. default:
  1278. usage();
  1279. } ARGEND;
  1280. Binit(&bout, 1, OWRITE);
  1281. ds("R", "&#174;");
  1282. doconvert();
  1283. exits(nil);
  1284. }
  1285. void
  1286. g_notyet(int, char **argv)
  1287. {
  1288. fprint(2, "ms2html: .%s not yet supported\n", argv[0]);
  1289. }
  1290. void
  1291. g_ignore(int, char **argv)
  1292. {
  1293. if(quiet)
  1294. return;
  1295. fprint(2, "ms2html: line %d: ignoring .%s\n", ssp->lno, argv[0]);
  1296. }
  1297. void
  1298. g_PP(int, char**)
  1299. {
  1300. dohanginghead();
  1301. closel();
  1302. closefont();
  1303. Bprint(&bout, "<P>\n");
  1304. paragraph = 1;
  1305. }
  1306. void
  1307. g_LP(int, char**)
  1308. {
  1309. dohanginghead();
  1310. closel();
  1311. closefont();
  1312. Bprint(&bout, "<br>&#32;<br>\n");
  1313. }
  1314. /* close a list */
  1315. void
  1316. closel(void)
  1317. {
  1318. g_P2(1, nil);
  1319. dohangingau();
  1320. if(paragraph){
  1321. Bprint(&bout, "</P>\n");
  1322. paragraph = 0;
  1323. }
  1324. switch(list){
  1325. case Lordered:
  1326. Bprint(&bout, "</ol>\n");
  1327. break;
  1328. case Lunordered:
  1329. Bprint(&bout, "</ul>\n");
  1330. break;
  1331. case Lother:
  1332. case Ldef:
  1333. Bprint(&bout, "</dl>\n");
  1334. break;
  1335. }
  1336. list = 0;
  1337. }
  1338. void
  1339. g_IP(int argc, char **argv)
  1340. {
  1341. switch(list){
  1342. default:
  1343. closel();
  1344. if(argc > 1){
  1345. if(strcmp(argv[1], "1") == 0){
  1346. list = Lordered;
  1347. listnum = 1;
  1348. Bprint(&bout, "<OL>\n");
  1349. } else if(strcmp(argv[1], "\\(bu") == 0){
  1350. list = Lunordered;
  1351. Bprint(&bout, "<UL>\n");
  1352. } else {
  1353. list = Lother;
  1354. Bprint(&bout, "<DL COMPACT>\n");
  1355. }
  1356. } else {
  1357. list = Lother;
  1358. Bprint(&bout, "<DL>\n");
  1359. }
  1360. break;
  1361. case Lother:
  1362. case Lordered:
  1363. case Lunordered:
  1364. break;
  1365. }
  1366. switch(list){
  1367. case Lother:
  1368. Bprint(&bout, "<DT>");
  1369. if(argc > 1)
  1370. printarg(argv[1]);
  1371. else
  1372. Bprint(&bout, "<DT>&#32;");
  1373. Bprint(&bout, "<DD>\n");
  1374. break;
  1375. case Lordered:
  1376. case Lunordered:
  1377. Bprint(&bout, "<LI>\n");
  1378. break;
  1379. }
  1380. }
  1381. /*
  1382. * .5i is one <DL><DT><DD>
  1383. */
  1384. void
  1385. g_in(int argc, char **argv)
  1386. {
  1387. float f;
  1388. int delta, x;
  1389. char *p;
  1390. f = indent/0.5;
  1391. delta = f;
  1392. if(argc <= 1){
  1393. indent = 0.0;
  1394. } else {
  1395. f = strtod(argv[1], &p);
  1396. switch(*p){
  1397. case 'i':
  1398. break;
  1399. case 'c':
  1400. f = f / 2.54;
  1401. break;
  1402. case 'P':
  1403. f = f / 6;
  1404. break;
  1405. default:
  1406. case 'u':
  1407. case 'm':
  1408. f = f * (12 / 72);
  1409. break;
  1410. case 'n':
  1411. f = f * (6 / 72);
  1412. break;
  1413. case 'p':
  1414. f = f / 72.0;
  1415. break;
  1416. }
  1417. switch(argv[1][0]){
  1418. case '+':
  1419. case '-':
  1420. indent += f;
  1421. break;
  1422. default:
  1423. indent = f;
  1424. break;
  1425. }
  1426. }
  1427. if(indent < 0.0)
  1428. indent = 0.0;
  1429. f = (indent/0.5);
  1430. x = f;
  1431. delta = x - delta;
  1432. while(delta < 0){
  1433. Bprint(&bout, "</DL>\n");
  1434. delta++;
  1435. }
  1436. while(delta > 0){
  1437. Bprint(&bout, "<DL><DT><DD>\n");
  1438. delta--;
  1439. }
  1440. }
  1441. void
  1442. g_HP(int, char**)
  1443. {
  1444. switch(list){
  1445. default:
  1446. closel();
  1447. list = Ldef;
  1448. hangingdt = 1;
  1449. Bprint(&bout, "<DL><DT>\n");
  1450. break;
  1451. case Ldef:
  1452. if(hangingdt)
  1453. Bprint(&bout, "<DD>");
  1454. Bprint(&bout, "<DT>");
  1455. hangingdt = 1;
  1456. break;
  1457. }
  1458. }
  1459. void
  1460. g_SH(int, char**)
  1461. {
  1462. dohanginghead();
  1463. dohangingcenter();
  1464. closel();
  1465. closefont();
  1466. Bprint(&bout, "<H%d>", HH);
  1467. hanginghead = HH;
  1468. }
  1469. void
  1470. g_NH(int argc, char **argv)
  1471. {
  1472. int i, level;
  1473. closel();
  1474. closefont();
  1475. dohangingcenter();
  1476. if(argc == 1)
  1477. level = 0;
  1478. else {
  1479. level = atoi(argv[1])-1;
  1480. if(level < 0 || level >= Maxnh)
  1481. level = Maxnh - 1;
  1482. }
  1483. nh[level]++;
  1484. Bprint(&bout, "<H%d>", HH);
  1485. hanginghead = HH;
  1486. Bprint(&bout, "%d", nh[0]);
  1487. for(i = 1; i <= level; i++)
  1488. Bprint(&bout, ".%d", nh[i]);
  1489. Bprint(&bout, " ");
  1490. for(i = level+1; i < Maxnh; i++)
  1491. nh[i] = 0;
  1492. }
  1493. void
  1494. g_TL(int, char**)
  1495. {
  1496. char *p, *np;
  1497. char name[128];
  1498. closefont();
  1499. if(!titleseen){
  1500. if(!title){
  1501. /* get base part of filename */
  1502. p = strrchr(ssp->filename, '/');
  1503. if(p == nil)
  1504. p = ssp->filename;
  1505. else
  1506. p++;
  1507. strncpy(name, p, sizeof(name));
  1508. name[sizeof(name)-1] = 0;
  1509. /* dump any extensions */
  1510. np = strchr(name, '.');
  1511. if(np)
  1512. *np = 0;
  1513. title = p;
  1514. }
  1515. Bprint(&bout, "<title>\n");
  1516. Bprint(&bout, "%s\n", title);
  1517. Bprint(&bout, "</title>\n");
  1518. Bprint(&bout, "<body BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\" LINK=\"#0000FF\" VLINK=\"#330088\" ALINK=\"#FF0044\">\n");
  1519. titleseen = 1;
  1520. }
  1521. Bprint(&bout, "<center>");
  1522. hangingcenter = 1;
  1523. Bprint(&bout, "<H%d>", 1);
  1524. hanginghead = 1;
  1525. }
  1526. void
  1527. dohangingcenter(void)
  1528. {
  1529. if(hangingcenter){
  1530. Bprint(&bout, "</center>");
  1531. hangingcenter = 1;
  1532. }
  1533. }
  1534. void
  1535. g_AU(int, char**)
  1536. {
  1537. closel();
  1538. dohanginghead();
  1539. Bprint(&bout, "<DL><DD><I>");
  1540. hangingau = 1;
  1541. }
  1542. void
  1543. pushfont(Font *f)
  1544. {
  1545. if(fsp == Maxfsp)
  1546. return;
  1547. if(fsp >= 0 && fstack[fsp])
  1548. Bprint(&bout, "%s", fstack[fsp]->end);
  1549. if(f != nil)
  1550. Bprint(&bout, "%s", f->start);
  1551. fstack[++fsp] = f;
  1552. }
  1553. void
  1554. popfont(void)
  1555. {
  1556. if(fsp >= 0){
  1557. if(fstack[fsp])
  1558. Bprint(&bout, "%s", fstack[fsp]->end);
  1559. fsp--;
  1560. }
  1561. }
  1562. /*
  1563. * for 3 args print arg3 \fxarg1\fP arg2
  1564. * for 2 args print arg1 \fxarg2\fP
  1565. * for 1 args print \fxarg1\fP
  1566. */
  1567. void
  1568. font(Font *f, int argc, char **argv)
  1569. {
  1570. if(argc == 1){
  1571. pushfont(nil);
  1572. return;
  1573. }
  1574. if(argc > 3)
  1575. printarg(argv[3]);
  1576. pushfont(f);
  1577. printarg(argv[1]);
  1578. popfont();
  1579. if(argc > 2)
  1580. printarg(argv[2]);
  1581. Bprint(&bout, "\n");
  1582. }
  1583. void
  1584. closefont(void)
  1585. {
  1586. if(fsp >= 0 && fstack[fsp])
  1587. Bprint(&bout, "%s", fstack[fsp]->end);
  1588. fsp = -1;
  1589. }
  1590. void
  1591. g_B(int argc, char **argv)
  1592. {
  1593. font(&bfont, argc, argv);
  1594. }
  1595. void
  1596. g_R(int argc, char **argv)
  1597. {
  1598. font(nil, argc, argv);
  1599. }
  1600. void
  1601. g_BI(int argc, char **argv)
  1602. {
  1603. font(&bifont, argc, argv);
  1604. }
  1605. void
  1606. g_CW(int argc, char **argv)
  1607. {
  1608. font(&cwfont, argc, argv);
  1609. }
  1610. char*
  1611. lower(char *p)
  1612. {
  1613. char *x;
  1614. for(x = p; *x; x++)
  1615. if(*x >= 'A' && *x <= 'Z')
  1616. *x -= 'A' - 'a';
  1617. return p;
  1618. }
  1619. void
  1620. g_I(int argc, char **argv)
  1621. {
  1622. int anchor;
  1623. char *p;
  1624. anchor = 0;
  1625. if(argc > 2){
  1626. p = argv[2];
  1627. if(p[0] == '(')
  1628. if(p[1] >= '0' && p[1] <= '9')
  1629. if(p[2] == ')'){
  1630. anchor = 1;
  1631. Bprint(&bout, "<A href=\"/magic/man2html/%c/%s\">",
  1632. p[1], lower(argv[1]));
  1633. }
  1634. }
  1635. font(&ifont, argc, argv);
  1636. if(anchor)
  1637. Bprint(&bout, "</A>");
  1638. }
  1639. void
  1640. g_br(int, char**)
  1641. {
  1642. if(hangingdt){
  1643. Bprint(&bout, "<dd>");
  1644. hangingdt = 0;
  1645. }else
  1646. Bprint(&bout, "<br>\n");
  1647. }
  1648. void
  1649. g_P1(int, char**)
  1650. {
  1651. if(example == 0){
  1652. example = 1;
  1653. Bprint(&bout, "<DL><DT><DD><TT><PRE>\n");
  1654. }
  1655. }
  1656. void
  1657. g_P2(int, char**)
  1658. {
  1659. if(example){
  1660. example = 0;
  1661. Bprint(&bout, "</PRE></TT></DL>\n");
  1662. }
  1663. }
  1664. void
  1665. g_SM(int, char **argv)
  1666. {
  1667. Bprint(&bout, "%s", argv[1]);
  1668. }
  1669. void
  1670. g_ft(int argc, char **argv)
  1671. {
  1672. if(argc < 2){
  1673. pushfont(nil);
  1674. return;
  1675. }
  1676. switch(argv[1][0]){
  1677. case '3':
  1678. case 'B':
  1679. pushfont(&bfont);
  1680. break;
  1681. case '2':
  1682. case 'I':
  1683. pushfont(&ifont);
  1684. break;
  1685. case '4':
  1686. pushfont(&bifont);
  1687. break;
  1688. case '5':
  1689. pushfont(&cwfont);
  1690. break;
  1691. case 'P':
  1692. popfont();
  1693. break;
  1694. case 'R':
  1695. default:
  1696. pushfont(nil);
  1697. break;
  1698. }
  1699. }
  1700. void
  1701. g_sp(int argc, char **argv)
  1702. {
  1703. int n;
  1704. n = 1;
  1705. if(argc > 1){
  1706. n = atoi(argv[1]);
  1707. if(n < 1)
  1708. n = 1;
  1709. if(argv[1][strlen(argv[1])-1] == 'i')
  1710. n *= 4;
  1711. }
  1712. if(n > 5){
  1713. Bprint(&bout, "<br>&#32;<br>\n");
  1714. Bprint(&bout, "<HR>\n");
  1715. Bprint(&bout, "<br>&#32;<br>\n");
  1716. } else
  1717. for(; n > 0; n--)
  1718. Bprint(&bout, "<br>&#32;<br>\n");
  1719. }
  1720. void
  1721. rm_loop(char *name, String **l)
  1722. {
  1723. String *s;
  1724. for(s = *l; s != nil; s = *l){
  1725. if(strcmp(name, s->name) == 0){
  1726. *l = s->next;
  1727. free(s->name);
  1728. free(s->val);
  1729. free(s);
  1730. break;
  1731. }
  1732. l = &s->next;
  1733. }
  1734. }
  1735. void
  1736. g_rm(int argc, char **argv)
  1737. {
  1738. Goobie *g;
  1739. char *name;
  1740. int i;
  1741. for(i = 1; i < argc; i++) {
  1742. name = argv[i];
  1743. rm_loop(name, &strings);
  1744. rm_loop(name, &macros);
  1745. for(g = gtab; g->name; g++)
  1746. if (strcmp(g->name, name) == 0) {
  1747. g->f = g_ignore;
  1748. break;
  1749. }
  1750. }
  1751. }
  1752. void
  1753. g_AB(int, char**)
  1754. {
  1755. closel();
  1756. dohangingcenter();
  1757. Bprint(&bout, "<center><H4>ABSTRACT</H4></center><DL><DD>\n");
  1758. }
  1759. void
  1760. g_AE(int, char**)
  1761. {
  1762. Bprint(&bout, "</DL>\n");
  1763. }
  1764. void
  1765. g_FS(int, char **)
  1766. {
  1767. char *argv[3];
  1768. argv[0] = "IP";
  1769. argv[1] = nil;
  1770. argv[2] = nil;
  1771. g_IP(1, argv);
  1772. Bprint(&bout, "NOTE:<I> ");
  1773. }
  1774. void
  1775. g_FE(int, char **)
  1776. {
  1777. Bprint(&bout, "</I><DT>&#32;<DD>");
  1778. closel();
  1779. Bprint(&bout, "<br>\n");
  1780. }
  1781. void
  1782. g_de(int argc, char **argv)
  1783. {
  1784. int r;
  1785. char *p, *cp;
  1786. String *m;
  1787. int len;
  1788. if(argc < 2)
  1789. return;
  1790. m = nil;
  1791. len = 0;
  1792. if(strcmp(argv[0], "am") == 0){
  1793. for(m = macros; m != nil; m = m->next)
  1794. if(strcmp(argv[1], m->name) == 0){
  1795. len = strlen(m->val);
  1796. break;
  1797. }
  1798. if(m == nil){
  1799. /* nothing to append to */
  1800. for(;;){
  1801. p = Brdline(&ssp->in, '\n');
  1802. if(p == nil)
  1803. break;
  1804. p[Blinelen(&ssp->in)-1] = 0;
  1805. if(strcmp(p, "..") == 0)
  1806. break;
  1807. }
  1808. return;
  1809. }
  1810. }
  1811. if(m == nil){
  1812. m = emalloc(sizeof(*m));
  1813. m->next = macros;
  1814. macros = m;
  1815. m->name = strdup(argv[1]);
  1816. m->val = nil;
  1817. len = 0;
  1818. }
  1819. /* read up to a .. removing double backslashes */
  1820. for(;;){
  1821. p = Brdline(&ssp->in, '\n');
  1822. if(p == nil)
  1823. break;
  1824. p[Blinelen(&ssp->in)-1] = 0;
  1825. if(strcmp(p, "..") == 0)
  1826. break;
  1827. m->val = realloc(m->val, len + Blinelen(&ssp->in)+1);
  1828. cp = m->val + len;
  1829. while(*p){
  1830. r = *p++;
  1831. if(r == '\\' && *p == '\\')
  1832. p++;
  1833. *cp++ = r;
  1834. }
  1835. *cp++ = '\n';
  1836. len = cp - m->val;
  1837. *cp = 0;
  1838. }
  1839. }
  1840. void
  1841. g_hrule(int, char**)
  1842. {
  1843. Bprint(&bout, "<HR>\n");
  1844. }
  1845. void
  1846. g_BX(int argc, char **argv)
  1847. {
  1848. Bprint(&bout, "<HR>\n");
  1849. printargs(argc, argv);
  1850. Bprint(&bout, "<HR>\n");
  1851. }
  1852. void
  1853. g_IH(int, char**)
  1854. {
  1855. Bprint(&bout, "Bell Laboratories, Naperville, Illinois, 60540\n");
  1856. }
  1857. void
  1858. g_MH(int, char**)
  1859. {
  1860. Bprint(&bout, "Bell Laboratories, Murray Hill, NJ, 07974\n");
  1861. }
  1862. void
  1863. g_PY(int, char**)
  1864. {
  1865. Bprint(&bout, "Bell Laboratories, Piscataway, NJ, 08854\n");
  1866. }
  1867. void
  1868. g_HO(int, char**)
  1869. {
  1870. Bprint(&bout, "Bell Laboratories, Holmdel, NJ, 07733\n");
  1871. }
  1872. void
  1873. g_QS(int, char**)
  1874. {
  1875. Bprint(&bout, "<BLOCKQUOTE>\n");
  1876. }
  1877. void
  1878. g_QE(int, char**)
  1879. {
  1880. Bprint(&bout, "</BLOCKQUOTE>\n");
  1881. }
  1882. void
  1883. g_RS(int, char**)
  1884. {
  1885. Bprint(&bout, "<DL><DD>\n");
  1886. }
  1887. void
  1888. g_RE(int, char**)
  1889. {
  1890. Bprint(&bout, "</DL>\n");
  1891. }
  1892. int gif;
  1893. void
  1894. g_startgif(int, char **argv)
  1895. {
  1896. int fd;
  1897. int pfd[2];
  1898. char *e, *p;
  1899. char name[32];
  1900. Dir *d;
  1901. if(strcmp(argv[0], "EQ") == 0)
  1902. e = ".EN";
  1903. else if(strcmp(argv[0], "TS") == 0)
  1904. e = ".TE";
  1905. else if(strcmp(argv[0], "PS") == 0)
  1906. e = ".PE";
  1907. else
  1908. return;
  1909. if(basename)
  1910. p = basename;
  1911. else{
  1912. p = strrchr(sstack[0].filename, '/');
  1913. if(p != nil)
  1914. p++;
  1915. else
  1916. p = sstack[0].filename;
  1917. }
  1918. snprint(name, sizeof(name), "%s.%d.gif", p, gif++);
  1919. fd = create(name, OWRITE, 0664);
  1920. if(fd < 0){
  1921. fprint(2, "ms2html: can't create %s: %r\n", name);
  1922. return;
  1923. }
  1924. if(pipe(pfd) < 0){
  1925. fprint(2, "ms2html: can't create pipe: %r\n");
  1926. close(fd);
  1927. return;
  1928. }
  1929. switch(rfork(RFFDG|RFPROC)){
  1930. case -1:
  1931. fprint(2, "ms2html: can't fork: %r\n");
  1932. close(fd);
  1933. return;
  1934. case 0:
  1935. dup(fd, 1);
  1936. close(fd);
  1937. dup(pfd[0], 0);
  1938. close(pfd[0]);
  1939. close(pfd[1]);
  1940. execl("/bin/troff2gif", "troff2gif", nil);
  1941. fprint(2, "ms2html: couldn't exec troff2gif: %r\n");
  1942. _exits(nil);
  1943. default:
  1944. close(fd);
  1945. close(pfd[0]);
  1946. fprint(pfd[1], ".ll 7i\n");
  1947. /* fprint(pfd[1], ".EQ\ndelim %s\n.EN\n", delim); */
  1948. /* fprint(pfd[1], ".%s\n", argv[0]); */
  1949. for(;;){
  1950. p = Brdline(&ssp->in, '\n');
  1951. if(p == nil)
  1952. break;
  1953. ssp->lno++;
  1954. ssp->rlno++;
  1955. if(write(pfd[1], p, Blinelen(&ssp->in)) < 0)
  1956. break;
  1957. if(strncmp(p, e, 3) == 0)
  1958. break;
  1959. }
  1960. close(pfd[1]);
  1961. waitpid();
  1962. d = dirstat(name);
  1963. if(d == nil)
  1964. break;
  1965. if(d->length == 0){
  1966. remove(name);
  1967. free(d);
  1968. break;
  1969. }
  1970. free(d);
  1971. fprint(2, "ms2html: created auxiliary file %s\n", name);
  1972. Bprint(&bout, "<br><img src=\"%s\"><br>\n", name);
  1973. break;
  1974. }
  1975. }
  1976. void
  1977. g_lf(int argc, char **argv)
  1978. {
  1979. if(argc > 2)
  1980. snprint(ssp->filename, sizeof(ssp->filename), argv[2]);
  1981. if(argc > 1)
  1982. ssp->rlno = atoi(argv[1]);
  1983. }
  1984. void
  1985. g_so(int argc, char **argv)
  1986. {
  1987. ssp->lno++;
  1988. ssp->rlno++;
  1989. if(argc > 1)
  1990. pushsrc(argv[1]);
  1991. }
  1992. void
  1993. g_BP(int argc, char **argv)
  1994. {
  1995. int fd;
  1996. char *p, *ext;
  1997. char name[32];
  1998. Dir *d;
  1999. if(argc < 2)
  2000. return;
  2001. p = strrchr(argv[1], '/');
  2002. if(p != nil)
  2003. p++;
  2004. else
  2005. p = argv[1];
  2006. ext = strrchr(p, '.');
  2007. if(ext){
  2008. if(strcmp(ext, ".jpeg") == 0
  2009. || strcmp(ext, ".gif") == 0){
  2010. Bprint(&bout, "<br><img src=\"%s\"><br>\n", argv[1]);
  2011. return;
  2012. }
  2013. }
  2014. snprint(name, sizeof(name), "%s.%d%d.gif", p, getpid(), gif++);
  2015. fd = create(name, OWRITE, 0664);
  2016. if(fd < 0){
  2017. fprint(2, "ms2html: can't create %s: %r\n", name);
  2018. return;
  2019. }
  2020. switch(rfork(RFFDG|RFPROC)){
  2021. case -1:
  2022. fprint(2, "ms2html: can't fork: %r\n");
  2023. close(fd);
  2024. return;
  2025. case 0:
  2026. dup(fd, 1);
  2027. close(fd);
  2028. execl("/bin/ps2gif", "ps2gif", argv[1], nil);
  2029. fprint(2, "ms2html: couldn't exec ps2gif: %r\n");
  2030. _exits(nil);
  2031. default:
  2032. close(fd);
  2033. waitpid();
  2034. d = dirstat(name);
  2035. if(d == nil)
  2036. break;
  2037. if(d->length == 0){
  2038. remove(name);
  2039. free(d);
  2040. break;
  2041. }
  2042. free(d);
  2043. fprint(2, "ms2html: created auxiliary file %s\n", name);
  2044. Bprint(&bout, "<br><img src=\"%s\"><br>\n", name);
  2045. break;
  2046. }
  2047. }
  2048. /* insert straight HTML into output */
  2049. void
  2050. g__H(int argc, char **argv)
  2051. {
  2052. int i;
  2053. for(i = 1; i < argc; i++)
  2054. Bprint(&bout, "%s ", argv[i]);
  2055. Bprint(&bout, "\n");
  2056. }
  2057. /* HTML page title */
  2058. void
  2059. g__T(int argc, char **argv)
  2060. {
  2061. if(titleseen)
  2062. return;
  2063. Bprint(&bout, "<title>\n");
  2064. printargs(argc, argv);
  2065. Bprint(&bout, "</title></head><body>\n");
  2066. titleseen = 1;
  2067. }
  2068. void
  2069. g_nr(int argc, char **argv)
  2070. {
  2071. char *val;
  2072. if (argc > 1) {
  2073. if (argc == 2)
  2074. val = "0";
  2075. else
  2076. val = argv[2];
  2077. dsnr(argv[1], val, &numregs);
  2078. }
  2079. }
  2080. void
  2081. zerodivide(void)
  2082. {
  2083. fprint(2, "stdin %d(%s:%d): division by 0\n",
  2084. ssp->lno, ssp->filename, ssp->rlno);
  2085. }
  2086. int
  2087. numval(char **pline, int recur)
  2088. {
  2089. char *p;
  2090. int neg, x, y;
  2091. x = neg = 0;
  2092. p = *pline;
  2093. while(*p == '-') {
  2094. neg = 1 - neg;
  2095. p++;
  2096. }
  2097. if (*p == '(') {
  2098. p++;
  2099. x = numval(&p, 1);
  2100. if (*p != ')')
  2101. goto done;
  2102. p++;
  2103. }
  2104. else while(*p >= '0' && *p <= '9')
  2105. x = 10*x + *p++ - '0';
  2106. if (neg)
  2107. x = -x;
  2108. if (recur)
  2109. for(;;) {
  2110. switch(*p++) {
  2111. case '+':
  2112. x += numval(&p, 0);
  2113. continue;
  2114. case '-':
  2115. x -= numval(&p, 0);
  2116. continue;
  2117. case '*':
  2118. x *= numval(&p, 0);
  2119. continue;
  2120. case '/':
  2121. y = numval(&p, 0);
  2122. if (y == 0) {
  2123. zerodivide();
  2124. x = 0;
  2125. goto done;
  2126. }
  2127. x /= y;
  2128. continue;
  2129. case '<':
  2130. if (*p == '=') {
  2131. p++;
  2132. x = x <= numval(&p, 0);
  2133. continue;
  2134. }
  2135. x = x < numval(&p, 0);
  2136. continue;
  2137. case '>':
  2138. if (*p == '=') {
  2139. p++;
  2140. x = x >= numval(&p, 0);
  2141. continue;
  2142. }
  2143. x = x > numval(&p, 0);
  2144. continue;
  2145. case '=':
  2146. if (*p == '=')
  2147. p++;
  2148. x = x == numval(&p, 0);
  2149. continue;
  2150. case '&':
  2151. x &= numval(&p, 0);
  2152. continue;
  2153. case ':':
  2154. x |= numval(&p, 0);
  2155. continue;
  2156. case '%':
  2157. y = numval(&p, 0);
  2158. if (!y) {
  2159. zerodivide();
  2160. goto done;
  2161. }
  2162. x %= y;
  2163. continue;
  2164. }
  2165. --p;
  2166. break;
  2167. }
  2168. done:
  2169. *pline = p;
  2170. return x;
  2171. }
  2172. int
  2173. iftest(char *p, char **bp)
  2174. {
  2175. char *p1;
  2176. int c, neg, rv;
  2177. rv = neg = 0;
  2178. if (*p == '!') {
  2179. neg = 1;
  2180. p++;
  2181. }
  2182. c = *p;
  2183. if (c >= '0' && c <= '9' || c == '+' || c == '-' || c == '('/*)*/) {
  2184. if (numval(&p,1) >= 1)
  2185. rv = 1;
  2186. goto done;
  2187. }
  2188. switch(c) {
  2189. case 't':
  2190. case 'o':
  2191. rv = 1;
  2192. case 'n':
  2193. case 'e':
  2194. p++;
  2195. goto done;
  2196. }
  2197. for(p1 = ++p; *p != c; p++)
  2198. if (!*p)
  2199. goto done;
  2200. for(p++;;) {
  2201. if (*p != *p1++) {
  2202. while(*p && *p++ != c);
  2203. goto done;
  2204. }
  2205. if (*p++ == c)
  2206. break;
  2207. }
  2208. rv = 1;
  2209. done:
  2210. if (neg)
  2211. rv = 1 - rv;
  2212. while(*p == ' ' || *p == '\t')
  2213. p++;
  2214. *bp = p;
  2215. return rv;
  2216. }
  2217. void
  2218. scanline(char *p, char *e, int wantnl)
  2219. {
  2220. int c;
  2221. Rune r;
  2222. while((c = getrune()) == ' ' || c == '\t') ;
  2223. while(p < e) {
  2224. if (c < 0)
  2225. break;
  2226. if (c < Runeself) {
  2227. if (c == '\n') {
  2228. if (wantnl)
  2229. *p++ = c;
  2230. break;
  2231. }
  2232. *p++ = c;
  2233. }
  2234. else {
  2235. r = c;
  2236. p += runetochar(p, &r);
  2237. }
  2238. c = getrune();
  2239. }
  2240. *p = 0;
  2241. }
  2242. void
  2243. pushbody(char *line)
  2244. {
  2245. char *b;
  2246. if (line[0] == '\\' && line[1] == '{' /*}*/ )
  2247. line += 2;
  2248. if (strsp < Maxmstack - 1) {
  2249. pushstr(b = strdup(line));
  2250. mustfree[strsp] = b;
  2251. }
  2252. }
  2253. void
  2254. skipbody(char *line)
  2255. {
  2256. int c, n;
  2257. if (line[0] != '\\' || line[1] != '{' /*}*/ )
  2258. return;
  2259. for(n = 1;;) {
  2260. while((c = getrune()) != '\\')
  2261. if (c < 0)
  2262. return;
  2263. c = getrune();
  2264. if (c == '{')
  2265. n++;
  2266. else if ((c == '}' && (c = getrune()) == '\n' && !--n)
  2267. || c < 0)
  2268. return;
  2269. }
  2270. }
  2271. int
  2272. ifstart(char *line, char *e, char **bp)
  2273. {
  2274. int it;
  2275. char *b;
  2276. b = copyline(line, e, 1);
  2277. ungetrune();
  2278. b[-1] = getrune();
  2279. scanline(b, e, 1);
  2280. it = iftest(line, bp);
  2281. return it;
  2282. }
  2283. void
  2284. g_ie(char *line, char *e)
  2285. {
  2286. char *b;
  2287. if (elsetop >= Maxif-1) {
  2288. fprint(2, "ms2html: .ie's too deep\n");
  2289. return;
  2290. }
  2291. if (ifwastrue[++elsetop] = ifstart(line, e, &b))
  2292. pushbody(b);
  2293. else
  2294. skipbody(b);
  2295. }
  2296. void
  2297. g_if(char *line, char *e)
  2298. {
  2299. char *b;
  2300. if (ifstart(line, e, &b))
  2301. pushbody(b);
  2302. else
  2303. skipbody(b);
  2304. }
  2305. void
  2306. g_el(char *line, char *e)
  2307. {
  2308. if (elsetop < 0)
  2309. return;
  2310. scanline(line, e, 1);
  2311. if (ifwastrue[elsetop--])
  2312. skipbody(line);
  2313. else
  2314. pushbody(line);
  2315. }
  2316. void
  2317. g_ig(int argc, char **argv)
  2318. {
  2319. char *p, *s;
  2320. s = "..";
  2321. if (argc > 1)
  2322. s = argv[1];
  2323. for(;;) {
  2324. p = Brdline(&ssp->in, '\n');
  2325. if(p == nil)
  2326. break;
  2327. p[Blinelen(&ssp->in)-1] = 0;
  2328. if(strcmp(p, s) == 0)
  2329. break;
  2330. }
  2331. }
  2332. void
  2333. g_ds(char *line, char *e)
  2334. {
  2335. char *b;
  2336. b = copyline(line, e, 1);
  2337. if (b > line) {
  2338. copyline(b, e, 0);
  2339. if (*b == '"')
  2340. b++;
  2341. ds(line, b);
  2342. }
  2343. }
  2344. void
  2345. g_as(char *line, char *e)
  2346. {
  2347. String *s;
  2348. char *b;
  2349. b = copyline(line, e, 1);
  2350. if (b == line)
  2351. return;
  2352. copyline(b, e, 0);
  2353. if (*b == '"')
  2354. b++;
  2355. for(s = strings; s != nil; s = s->next)
  2356. if(strcmp(line, s->name) == 0)
  2357. break;
  2358. if(s == nil){
  2359. ds(line, b);
  2360. return;
  2361. }
  2362. s->val = realloc(s->val, strlen(s->val) + strlen(b) + 1);
  2363. strcat(s->val, b);
  2364. }
  2365. void
  2366. g_BS(int argc, char **argv)
  2367. {
  2368. int i;
  2369. if (argc > 1 && !weBref) {
  2370. Bprint(&bout, "<a href=\"%s\"", argv[1]);
  2371. for(i = 2; i < argc; i++)
  2372. Bprint(&bout, " %s", argv[i]);
  2373. Bprint(&bout, ">");
  2374. weBref = 1;
  2375. }
  2376. }
  2377. void
  2378. g_BE(int, char**)
  2379. {
  2380. if (weBref) {
  2381. Bprint(&bout, "</a>");
  2382. weBref = 0;
  2383. }
  2384. }
  2385. void
  2386. g_LB(int argc, char **argv)
  2387. {
  2388. if (argc > 1) {
  2389. if (weBref)
  2390. g_BE(0,nil);
  2391. Bprint(&bout, "<a name=\"%s\"></a>", argv[1]);
  2392. }
  2393. }
  2394. void
  2395. g_RT(int, char**)
  2396. {
  2397. g_BE(0,nil);
  2398. dohanginghead();
  2399. closel();
  2400. closefont();
  2401. }