ms2html.c 40 KB

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