ms2html.c 41 KB

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