ms2html.c 39 KB

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