ms2html.c 40 KB

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