Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1612 lines
37 KiB

  1. COMMENT $
  2. CMACROS - assembly macros for interfacing to HLL
  3. (C)Copyright Microsoft Cor. 1990
  4. $
  5. ; Revision History
  6. ; 6.0 Initial Release of cmacros for MASM 6.0
  7. ;
  8. COMMENT $
  9. ; Note: There are some differences between this version of CMACROS
  10. ; and previous releases. The most signification is the fact
  11. ; that locals and parameter names are now scoped to the body
  12. ; of a procedure. To help ease this problem we have introduced
  13. ; a new directive cRet. This means that the following transformation
  14. ; can occur on your source to deal with parameters no referenced
  15. ; in the body of a procedure
  16. ;
  17. ; cProc cProc
  18. ; locals,parms locals,parms
  19. ; cBegin cBegin
  20. ; .... ...
  21. ; cEnd cRet
  22. ; error code referencing error code referencing
  23. ; locals and parms locals and params
  24. ; cEnd <nogen>
  25. ;
  26. ; The major reason for making locals and parameters scoped was
  27. ; the percieved benifit of error checking for defined labels in
  28. ; the procedure and the addition of codeView information on locals
  29. ; and parameters for functions.
  30. $
  31. .xcref ; Get rid of alot of symbols
  32. ; ??_out - output the given message to the console unless ?QUIET
  33. ; has been specified
  34. ;
  35. ; usage:
  36. ; ??_out <t>
  37. ; where:
  38. ; <t> is the message to output
  39. ??_out macro t
  40. ifndef ?QUIET
  41. echo t
  42. endif
  43. endm
  44. ; outif - output msg if name is non-zero. If name is undefined,
  45. ; set name =0, else set name to the default value.
  46. ;
  47. ; usage:
  48. ; outif name, defval, onmsg, offmsg
  49. ; where:
  50. ; name name of symbol
  51. ; defval default value to give symobl if not defined.
  52. ; if blank, then 0 will be used
  53. ; onmsg text to display if symbol is non-zero
  54. ; offmsg text to display if symbol is zero
  55. ;
  56. outif macro name:req, defval:=<0>, onmsg, offmsg
  57. ifndef name
  58. name = defval
  59. endif
  60. if name
  61. name = 1
  62. ifnb <onmsg>
  63. ??_out <! onmsg>
  64. endif
  65. else
  66. ifnb <offmsg>
  67. ??_out <! offmsg>
  68. endif
  69. endif
  70. endm
  71. ; ??error - output message and generate an assembly time error
  72. ;
  73. ; usage:
  74. ; ??error <t>
  75. ; where:
  76. ; t is the text to output
  77. ;
  78. ??error macro msg
  79. echo e r r o r ------ msg ;; to console
  80. .err e r r o r ------ msg ;; forced error by assembler
  81. endm
  82. ??_out <cMacros Version 6.00 - 1/1/91>
  83. ??_out <Copyright (C) Microsoft Corp. 1990-1991. All rights reserved.>
  84. ;
  85. ; Determine the memory model for cmacros. Default to small if
  86. ; no other model has been specified.
  87. ;
  88. ifdef ?SMALL
  89. memS=1
  90. endif
  91. ifdef ?MEDIUM
  92. memM=1
  93. endif
  94. ifdef ?COMPACT
  95. memC=1
  96. endif
  97. ifdef ?LARGE
  98. memL=1
  99. endif
  100. ifdef ?HUGE
  101. memH=1
  102. endif
  103. outif memS,0,<Small Model>
  104. outif memM,0,<Medium Model>
  105. outif memC,0,<Compact Model>
  106. outif memL,0,<Large Model>
  107. outif memH,0,<Huge Model>
  108. memMOD = memS + memM + memL + memC + memH
  109. if memMOD ne 1
  110. if memMOD eq 0
  111. memS=1 ; Assume small model
  112. outif memS,0,<Small Model>
  113. else
  114. ??error <must have only 1 memory model selected>
  115. endif
  116. endif
  117. sizec = memM + memL + memH ; Large Code models
  118. sizeC = sizec
  119. sized = memC + memL + memH ; Large Data models
  120. sizeD = sized
  121. ;
  122. ; Inform user of any other options selected
  123. ;
  124. outif ?DF,0,<No segments or groups will be defined>
  125. outif ?DFDATA,0,<No data segments will be defined>
  126. outif ?DFCODE,0,<No code segments will be defined>
  127. outif ?TF,0,<Epilogue sequences will assume valid SP>
  128. outif ?WIN,1,<Windows support>
  129. outif ?COW,0,<Character Windows support>
  130. outif ?PLM,1,<PL/M calling convention>
  131. outif ?NOATOMIC,0,<ATOMIC calling convention>
  132. outif ?NODATA,0,<NODATA module>
  133. ifdef ?CHKSTK
  134. ifdef ?CHKSTKPROC
  135. ??_out <! Private stack checking enabled>
  136. else
  137. ??_out <! Stack checking enabled>
  138. endif
  139. else
  140. ?CHKSTK = 0
  141. endif
  142. ifndef ?DOS5
  143. ?DOS5 = 0
  144. endif
  145. ;
  146. ; Setup some local variables to the Cmacros package
  147. ;
  148. ??CM_state = 0 ; 0 - inactive, 1-cProc, 2-cBegin,
  149. ??CM_RegSaveList textequ <> ; List of saved registers
  150. ??CM_ArgList textequ <>
  151. ;
  152. ; This function is used to paste together two text items to
  153. ; get a third text item.
  154. ;
  155. ??CM_Paste macro arg1:req, arg2:req
  156. exitm <arg1&arg2>
  157. endm
  158. ;
  159. ; This function is used to create a text macro containning the
  160. ; n-th local to a fuction definition.
  161. ;
  162. ??CM_addLocal macro arg1:req
  163. ??CM_Paste(??CM_local, %??CM_localCount) textequ <LOCAL arg1>
  164. ??CM_localCount = ??CM_localCount + 1
  165. endm
  166. ;
  167. ; This function is used to create a text macro containning the
  168. ; n-th parameter to a function definition
  169. ;
  170. ??CM_addParm macro arg1:req
  171. if ??CM_argCount EQ 20
  172. .err <CMACROS.INC: Cannot have more than 20 arguements to a procedure>
  173. endif
  174. ??CM_Paste(??CM_arg, %??CM_argCount) textequ <, arg1>
  175. ??CM_argCount = ??CM_argCount + 1
  176. endm
  177. ;
  178. ; This macro creates the prologue code for a cmacro defined function.
  179. ;
  180. ; Prologue sequences
  181. ;
  182. cPrologue macro procname, flags, cbParms, cbLocals, reglist, userparms
  183. ?ba=0 ;;not in a procedure
  184. ?pu=0 ;;initial public setting
  185. ?ia=0 ;;no special prolog/epilog
  186. ?rp=0 ;;no register parameters
  187. ??CM_UserDoesFrame=0 ;;don't use makeframe
  188. ?ff=0 ;;don't force frame setup
  189. ?pas=0 ;;process register save list
  190. ?pcc=?PLM ;;calling convention (C or PL/M)
  191. ;;
  192. ;; Look at all of the user parameters and make appropriate decisions
  193. ;;
  194. for x,<userparms>
  195. ifdef ??CM_Paste(??_cproc_, x)
  196. ??CM_Paste(??_cproc_, x)
  197. else
  198. ??error <e r r o r - unknown keyword x>
  199. .err
  200. endif
  201. endm
  202. ;;
  203. ;; Now start some error checking
  204. ;;
  205. if (??CM_Atomic eq 1) and (??CM_NoData eq 0) ;;ATOMIC requires NODATA
  206. ??error <ATOMIC specified without NODATA - ATOMIC ignored>
  207. ??CM_Atomic = 0 ;;clear the ATOMIC keyword
  208. endif
  209. if flags AND 020h ;;if a far procedure
  210. if ??CM_WinFarProc ;;if windows
  211. ife ??CM_Atomic ;;if not ATOMIC
  212. ife ?COW ;; COW dos not save DS
  213. ?ia=2 ;; adjust locals for saved ds
  214. ; ?pas = ?pas and (not ?ds) ;;no need for extra save
  215. endif
  216. endif
  217. endif
  218. else
  219. ??CM_WinFarProc=0 ;;not a far windows procedure
  220. endif
  221. ; ?pas = ?pas and (not (?sp+?cs+?ss)) ;;make no sense to save these
  222. if ??CM_UserDoesFrame ;;don't save these if user frame
  223. ; ?pas = ?pas and (not (?bp+?si+?di))
  224. endif
  225. if ??CM_UserDoesFrame ;;if user frame
  226. if ??CM_NoData
  227. ??error <NODATA encountered in &n - user frame ignored>
  228. ??CM_UserDoesFrame=0
  229. endif
  230. endif
  231. if ??CM_UserDoesFrame ;;if user frame
  232. if ?rp ;;If register parameters
  233. ??error <parmR encountered in &n - user frame ignored>
  234. ??CM_UserDoesFrame=0
  235. endif
  236. endif
  237. ?cpd=0 ;;terminate current proc def
  238. ifidn <g>,<nogen> ;;if nogen, then cannot have locals
  239. if cbLocals + cbParms + ?rp ;; saved regs, or parmRs
  240. ??_out <cBegin - possibly invalid use of nogen>
  241. endif
  242. else ;;else must generate a frame
  243. ;;
  244. ;; Allow the user to specify his own routine which is going to
  245. ;; do the frame set-up for this procedure
  246. ;;
  247. if ??CM_UserDoesFrame ;;if user frame code specified
  248. ?mf c,cbLocals,%?po ;; call user's makeframe
  249. for reg,reglist ;; save specified registers
  250. push reg
  251. endm
  252. else
  253. if ??CM_WinFarProc ;;if a far windows procedure
  254. ife ??CM_NoData ;;if not NODATA,
  255. mov ax,ds ;; then set AX = current ds, and ;@
  256. nop ;; leave room for MOV AX,1234h ;@
  257. endif
  258. ife ??CM_Atomic ;;if not ATOMIC, far frame must be set
  259. ife ?DOS5 ;;if not DOS5, then set far frame flag
  260. inc bp ;; by incrementing the old bp ;@
  261. endif
  262. push bp ;@
  263. mov bp,sp ;@
  264. ife ?COW ;; save DS not needed for CW
  265. push ds ;@
  266. endif
  267. else ;;ATOMIC procedure
  268. if ?ff+cbLocals+cbParms+?rp ;;if any locals or parameters
  269. push bp ;; then must set frame pointer ;@
  270. mov bp,sp ;; to be able to access them ;@
  271. endif
  272. endif
  273. ife ??CM_NoData ;;if not NODATA, then AX should
  274. mov ds,ax ;; have the ds to use ;@
  275. endif
  276. else ;;not windows. use standard prolog
  277. if ?ff+cbLocals+cbParms+?rp ;;if any locals or parameters
  278. push bp ;; then must set frame pointer ;@
  279. mov bp,sp ;; to be able to access them ;@
  280. endif
  281. endif
  282. if ?rp ;;if parmR's, push them before
  283. ??CM_UserDoesFrame=0 ;; allocating locals and saving
  284. rept ?rp ;; the autosave registers
  285. uconcat mpush,,?rp,%??CM_UserDoesFrame
  286. ??CM_UserDoesFrame=??CM_UserDoesFrame+1
  287. endm
  288. endif
  289. if cbLocals ;;if locals to allocate
  290. if ?CHKSTK ;;if stack checking enabled
  291. ifdef ?CHKSTKPROC ;;if user supplied stack checking
  292. ?CHKSTKPROC %cbLocals ;; invoke it with bytes requested
  293. else
  294. mov ax,cbLocals ;;invoke default stack checking ;@
  295. ife cc
  296. call _chkstk ;@
  297. else
  298. call chkstk ;@
  299. endif
  300. endif
  301. else ;;no stack checking
  302. sub sp,cbLocals ;; allocate any local storage ;@
  303. endif
  304. endif
  305. endif
  306. for reg,reglist ;;save autosave registers
  307. push reg
  308. endm
  309. endif ;; No Gen
  310. ifdef ?PROFILE ;;if profiling enabled
  311. if c ;; and a far procedure
  312. call StartNMeas ;; invoke profile start procedure ;@
  313. endif
  314. endif
  315. exitm %(cbLocals+?ia)
  316. endm
  317. ;
  318. ; This macro will define the epilogue sequences for CMACROS
  319. ; functions.
  320. ;
  321. ; Epilog sequences
  322. cEpilog macro procname, flags, cbParms, cbLocals, reglist, userparms
  323. if ??CM_nogen ;; Nogen the cEnd --
  324. exitm
  325. endif
  326. ?ba=0 ;;no longer in a procedure
  327. ifidn <g>,<nogen> ;;if nogen, then cannot have parmRs
  328. if a+r+lc ;; locals, or saved registers
  329. ??_out <cEnd - possibly invalid use of nogen>
  330. endif
  331. else ;;else must remove the frame
  332. ifdef ?PROFILE ;;if profiling enabled
  333. if flags AND 020H ;; and a far procedure
  334. call StopNMeas ;; invoke profile stop procedure
  335. endif ;; (doesn't trash DX:AX)
  336. endif ;; ?PROFILE
  337. for reg,reglist ;;restore autosaved registers
  338. pop reg
  339. endm
  340. if ??CM_UserDoesFrame ;;if to use the "makeframe" procedure
  341. db 0c3h ;; near return to user's makeframe @
  342. else
  343. if ??CM_WinFarProc ;;if far win proc, use special epilog
  344. ife ??CM_Atomic ;;if not ATOMIC, bp was pushed
  345. ife ?COW ;; restore DS not needed for CW
  346. if (?TF eq 0) or (cbLocals+?rp) ;;if cannot assume valid sp
  347. lea sp,-2+[bp] ;; or locals or parmR's, get valid SP @
  348. endif
  349. pop ds ;;restore saved ds and bp @
  350. else
  351. if (?TF eq 0) or (cbLocals+?rp) ;;if cannot assume valid sp
  352. mov sp,bp
  353. endif
  354. endif
  355. pop BP ;; @
  356. ife ?DOS5 ;;if not DOS5, bp was
  357. dec BP ;; incremented to mark far frame @
  358. endif
  359. else ;;ATOMIC frame was set up
  360. if memS32
  361. leave
  362. else
  363. if (?TF eq 0) or (cbLocals+?rp) ;;if cannot assume valid sp
  364. mov SP,BP ;; or locals or parmR's, get valid SP @
  365. endif
  366. if cbLocals+cbParms+?rp
  367. pop BP ;@
  368. endif
  369. endif
  370. endif
  371. else ;;non-windows standard epilog
  372. if ?ff+cbLocals+cbParms+?rp ;;if any parameters
  373. if (?TF eq 0) or (cbLocals+?rp) ;;if cannot assume valid SP
  374. mov SP,BP ;; or locals or parmR's, get valid SP;@
  375. endif
  376. pop BP ;@
  377. endif
  378. endif ;; Far Win Proc
  379. ife flags AND 010H ;;if Pascal calling convention
  380. ret cbParms ;; return and remove paramteres ;@
  381. else ;;else
  382. ret ;; return ;@
  383. endif
  384. endif ;; User makes frame
  385. endif ;; noGen
  386. endm
  387. ;
  388. ; cProc - This macro is used to define the start of a procedure in CMACROS.
  389. ;
  390. ; PARAMETERS:
  391. ; pname - The name of the procedure to be defined. This field is
  392. ; required to be present.
  393. ; attribs - This is a list of attributes which may be placed on the
  394. ; function being defined.
  395. ; autoSave - This is an optional list of registers which are to be
  396. ; saved and restored during the prologue/epilogue processing
  397. ;
  398. cProc macro pname:REQ, attribs, autoSave
  399. IF ??CM_state NE 0 ;; No nesting of functions allowed
  400. .err <CMACROS.INC: Cannot nest procedure definitions>
  401. endif
  402. ;
  403. ; Setup some state variables to start the procedure definition
  404. ;
  405. ??CM_state = 1 ;; Set state variable to seen cProc
  406. ??CM_ProcName EQU <pname>
  407. ??CM_ProcAutoSave EQU <autoSave>
  408. ??CM_localCount = 0
  409. ??CM_argCount = 0
  410. ??CM_langType EQU <>
  411. ??CM_WinFarProc=?WIN ;;default far procedure (win or not)
  412. ??CM_NoData=?NODATA ;;default NODATA flag
  413. ??CM_Atomic=?NOATOMIC ;;default is not ATOMIC
  414. repeat 20 ;; Clear all parameter textmacros
  415. ??CM_Paste(??CM_arg, %??CM_argCount) textequ <>
  416. ??CM_argCount = ??CM_argCount + 1
  417. endm
  418. ??CM_argCount = 0
  419. ife sizec ;; Set the default distance
  420. dist equ <NEAR>
  421. else
  422. dist equ <FAR>
  423. endif
  424. vis equ <> ;; Set the default visibility
  425. for arg,<attribs> ;; Look at the attribute list
  426. ifidn <arg>, <FAR>
  427. dist equ <FAR>
  428. elseifidn <arg>,<NEAR>
  429. dist equ <NEAR>
  430. elseifidn <arg>,<PUBLIC>
  431. vis equ <PUBLIC>
  432. elseifidn <arg>,<PRIVATE>
  433. vis equ <PRIVATE>
  434. elseifidn <arg>,<LOCAL> ;; Ignore -- only for CRT
  435. elseifidn <arg>,<PASCAL>
  436. ??CM_langType equ <PASCAL>
  437. elseifidn <arg>,<C>
  438. ??CM_langType equ <C>
  439. elseifidn <arg>,<WIN>
  440. ??CM_WinFarProc=1
  441. elseifidn <arg>,<NOWIN>
  442. ??CM_WinFarProc=0
  443. elseifidn <arg>,<NODATA>
  444. ??CM_NoData=1
  445. elseifidn <arg>,<ATOMIC>
  446. ??CM_Atomic=1
  447. else
  448. % .err <CMACROS.INC: cProc -- Unknown arguement '&arg'>
  449. endif
  450. endm
  451. option prologue:cPrologue ;; Change to our prologue sequence
  452. option epilogue:none ;; rets from here on are just rets
  453. endm
  454. ;
  455. cBegin macro pname
  456. local t2
  457. IF ??CM_state NE 1 ;; Must follow cProc
  458. .err <CMACROS.INC: cBegin must follow a cProc>
  459. endif
  460. ??CM_nogen = 0
  461. ifnb <pname>
  462. ifidn <pname>,<nogen>
  463. ??CM_nogen = 1
  464. elseifdif ??CM_ProcName, <pname>
  465. % echo <cBegin name (&pname) must match name on preceding cProc (&??CM_ProcName>
  466. endif
  467. endif
  468. ??CM_state = 2 ;; Seen a cBegin
  469. % setDefLangType ??CM_langType
  470. macroarg EQU <>
  471. ifnb ??CM_ProcAutoSave
  472. ??uses CATSTR <uses >, ??CM_ProcAutoSave
  473. t2 = @InStr(, %??uses, <,>)
  474. while t2 NE 0
  475. ??uses CATSTR @SubStr(<%??uses>, 1, %t2-1), < >, @SubStr(<%??uses>, %t2+1)
  476. t2 = @InStr(, %??uses, <,>)
  477. endm
  478. else
  479. ??uses textequ <>
  480. endif
  481. ifidn defLangType,<C>
  482. % ??CM_Paste(_, %??CM_ProcName) textequ <??CM_ProcName>
  483. endif
  484. ??CM_ProcName proc dist defLangType vis macroarg ??uses ??CM_arg0 ??CM_arg1 ??CM_arg2 ??CM_arg3 ??CM_arg4 ??CM_arg5 ??CM_arg6 ??CM_arg7 ??CM_arg8 ??CM_arg9 ??CM_arg10 ??CM_arg11 ??CM_arg12 ??CM_arg13 ??CM_arg14 ??CM_arg15 ??CM_arg16 ??CM_arg17 ??CM_arg18 ??CM_arg19
  485. ??CM_ProcAutoSave EQU <>
  486. t2 = 0
  487. repeat ??CM_localCount
  488. ??CM_Paste(??CM_local, %t2)
  489. t2 = t2 + 1
  490. endm
  491. endm
  492. ;
  493. cEnd macro pname
  494. IF ??CM_state NE 2 ;; Must follow a cEnd
  495. .err <cEnd must follow a cProc>
  496. endif
  497. ??CM_nogen = 0
  498. ifnb <pname>
  499. ifidn <pname>,<nogen>
  500. ??CM_nogen = 1
  501. elseifdif ??CM_ProcName, <pname>
  502. % echo <cEnd name (&pname) must match preceeding cProc name (&??CM_ProcName)>
  503. endif
  504. endif
  505. option epilogue:cEpilog
  506. ret
  507. option prologue:prologuedef
  508. option epilogue:epiloguedef
  509. ??CM_ProcName endp
  510. ??CM_state = 0 ;; not in a function
  511. endm
  512. ;
  513. ;
  514. cRet macro
  515. IF ??CM_state NE 2 ;; Must follow a cBegin
  516. .err <cRet must follow a cProc>
  517. endif
  518. option epilogue:cEpilog
  519. ret
  520. option epilogue:none
  521. endm
  522. ;
  523. ; createSeg is a macro that sets up a segment definition and
  524. ; a logical name for that segment. The logical name can
  525. ; be used to egner the segment, but it cannot be used for anyting
  526. ; else.
  527. ;
  528. ; usage:
  529. ; createSeg n, ln, a, co, cl, grp
  530. ; where:
  531. ; n is the physical name of the segment
  532. ; ln is the name it is to be invoked by
  533. ; a is the alignment, and is optional
  534. ; co is the combine type, and is optional
  535. ; cl is the class, and is optional
  536. ; grp is the name of the group that contains the segment
  537. ;
  538. createSeg macro segName, logName, aalign, combine, class, grp
  539. ifnb <class>
  540. segName segment aalign combine '&class'
  541. else
  542. segName segment aalign combine
  543. endif
  544. segName ends
  545. ifnb <grp>
  546. grp GROUP segName
  547. logName&OFFSET equ offset grp:
  548. logName&BASE equ grp
  549. else
  550. logName&OFFSET equ offset segName:
  551. logName&BASE equ segName
  552. endif
  553. logName&_sbegin macro
  554. segName segment
  555. sEnd macro name
  556. ifnb <name>
  557. ifdifi <name>,<logName>
  558. % echo <sEnd name does not match sBegin logName>
  559. endif
  560. endif
  561. segName ends
  562. purge sEnd
  563. endm
  564. endm
  565. ifnb <grp>
  566. logName&_assumes macro s
  567. assume s:grp
  568. endm
  569. else
  570. logName&_assumes macro s
  571. assume s:segName
  572. endm
  573. endif
  574. endm
  575. sBegin macro name:req
  576. name&_sbegin
  577. endm
  578. ; assumes is a macro that will set up the assumes for a segment
  579. ; or group created with the createSeg macro. If the assumed
  580. ; value passed in isn't known, then a normal assume is made.
  581. ;
  582. ; usage:
  583. ; assumes s,g
  584. ;
  585. ; where:
  586. ; s is the register to make the assumption about
  587. ; g is the value to assume is in it
  588. assumes macro s,ln
  589. ifndef ln&_assumes
  590. assume s:ln
  591. else
  592. ln&_assumes s
  593. endif
  594. endm
  595. ;
  596. ; defGrp
  597. ;
  598. defGrp macro foo:vararg
  599. endm
  600. ; setDefLangType
  601. setDefLangType macro overLangType
  602. ifnb <overLangType>
  603. ifidn <overLangType>,<C>
  604. defLangType textequ <C>
  605. elseifidn <overLangType>,<PASCAL>
  606. defLangType textequ <PASCAL>
  607. elseifidn <overLangType>,<PLM>
  608. defLangType textequ <PASCAL>
  609. else
  610. % .err <Illegal Language Type specified 'overLangType'>
  611. endif
  612. else ; !nb <overLangType>
  613. if ?PLM EQ 1
  614. defLangType textequ <PASCAL>
  615. elseif ?PLM EQ 0
  616. defLangType textequ <C>
  617. else
  618. .err <Illegal value for ?PLM>
  619. endif
  620. endif ; nb <overLangType>
  621. endm
  622. ifndef ?NOSTATIC
  623. .xcref
  624. .xcref staticB, staticW, staticD, staticQ, staticT, staticCP, staticDP, staticI
  625. .cref
  626. ; staticX - define static data of type X
  627. ;
  628. ; usage:
  629. ; staticX n, i, s
  630. ;
  631. ; where:
  632. ; X is the type of the variable: b=byte, w=word, d=dword
  633. ; q=quad word, t=ten bytes, cp=code pointer,
  634. ; dp=data pointer, i=int
  635. ; n is the name of the given variable
  636. ; i is the initial value of the variable
  637. ; s is the duplication factor
  638. ;
  639. ; statics are always pascal symbols and non-public. If they are required
  640. ; to be public then globalX should be used.
  641. staticB macro name:req, initVal:=<?>, repCount
  642. ifnb <repCount>
  643. name db repCount dup (initVal)
  644. else
  645. name db initVal
  646. endif
  647. endm
  648. staticW macro name:req, initVal:=<?>, repCount
  649. ifnb <repCount>
  650. name dw repCount dup (initVal)
  651. else
  652. name dw initVal
  653. endif
  654. endm
  655. staticD macro name:req, initVal:=<?>, repCount
  656. ifnb <repCount>
  657. name dd repCount dup (initVal)
  658. else
  659. name dd initVal
  660. endif
  661. endm
  662. staticI macro name:req, initVal:=<?>, repCount
  663. ifnb <repCount>
  664. name asmI repCount dup (initVal)
  665. else
  666. name asmI initVal
  667. endif
  668. endm
  669. staticQ macro name:req, initVal:=<?>, repCount
  670. ifnb <repCount>
  671. name dq repCount dup (initVal)
  672. else
  673. name dq initVal
  674. endif
  675. endm
  676. staticT macro name:req, initVal:=<?>, repCount
  677. ifnb <repCount>
  678. name dt repCount dup (initVal)
  679. else
  680. name dt initVal
  681. endif
  682. endm
  683. if sizec
  684. staticCP macro name:req, i, s
  685. staticD name,<i>,<s>
  686. endm
  687. else
  688. staticCP macro name:req, i, s
  689. staticW name,<i>,<s>
  690. endm
  691. endif
  692. if sized
  693. staticDP macro name:req, i, s
  694. staticD name,<i>,<s>
  695. endm
  696. else
  697. staticDP macro name:req, i, s
  698. staticW name,<i>,<s>
  699. endm
  700. endif
  701. endif ; ?NOSTATIC
  702. globalB macro name:req, initVal:=<?>, repCount, langType
  703. ??CM_gbl1 name, langType, initVal, repCount, DB
  704. endm
  705. globalW macro name:req, initVal:=<?>, repCount, langType
  706. ??CM_gbl1 name, langType, <initVal>, repCount, DW
  707. endm
  708. globalD macro name:req, initVal:=<?>, repCount, langType
  709. ??CM_gbl1 name, langType, <initVal>, repCount, DD
  710. endm
  711. globalQ macro name:req, initVal:=<?>, repCount, langType
  712. ??CM_gbl1 name, langType, initVal, repCount, DQ
  713. endm
  714. globalT macro name:req, initVal:=<?>, repCount, langType
  715. ??CM_gbl1 name, langType, initVal, repCount, DT
  716. endm
  717. if sizec
  718. globalCP macro n,i,s,c
  719. globalD <n>,<i>,<s>,<c>
  720. endm
  721. else
  722. globalCP macro n,i,s,c
  723. globalW <n>,<i>,<s>,<c>
  724. endm
  725. endif
  726. if sized
  727. globalDP macro n,i,s,c
  728. globalD <n>,<i>,<s>,<c>
  729. endm
  730. else
  731. globalDP macro n,i,s,c
  732. globalW <n>,<i>,<s>,<c>
  733. endm
  734. endif
  735. ??CM_gbl1 macro name, langType, initVal, repCount:=<1>, kind
  736. setDefLangType langType
  737. ifidn defLangType,<C>
  738. public _&name
  739. name textequ <_&name>
  740. _&name kind repCount dup (initVal)
  741. else
  742. public name
  743. name kind repCount dup (initVal)
  744. endif
  745. endm
  746. ifndef ?NOEXTERN
  747. .xcref
  748. .xcref externB, externW, externD, externQ, externT
  749. .xcref externNP, externFP, externP, externCP, externDP, externA
  750. .cref
  751. ; externX - define external data of type X
  752. ;
  753. ; usage:
  754. ; externX n,c
  755. ;
  756. ; where:
  757. ; X is the type of the variable: b=byte, w=word, d=dword
  758. ; q=qword, t=tbyte, cp=code pointer, dp=data pointer
  759. ; a=absolute, i=int
  760. ; n is a list of names to be defined
  761. ; c is the lanague convention. C for C or PASCAL or PLM for
  762. ; pascal. The default (?PLM flag) will be used if not specified
  763. externA macro names:req, langtype
  764. ??CM_ex1 <names>, langtype, ABS
  765. endm
  766. externB macro names:req, langtype
  767. ??CM_ex1 <names>, langtype, BYTE
  768. endm
  769. externW macro names:req, langtype
  770. ??CM_ex1 <names>, langtype, WORD
  771. endm
  772. externD macro names:req, langtype
  773. ??CM_ex1 <names>, langtype, DWORD
  774. endm
  775. externQ macro names:req, langtype
  776. ??CM_ex1 <names>, langtype, QWORD
  777. endm
  778. externT macro names:req, langtype
  779. ??CM_ex1 <names>, langtype, TBYTE
  780. endm
  781. externNP macro names:req, langtype
  782. ??CM_ex1 <names>, langtype, NEAR
  783. endm
  784. externFP macro names:req, langtype
  785. ??CM_ex1 <names>, langtype, FAR
  786. endm
  787. if sizec
  788. externP macro n,c
  789. externFP <n>,c
  790. endm
  791. externCP macro n,c
  792. externD <n>,c
  793. endm
  794. else
  795. externP macro n,c
  796. externNP <n>,c
  797. endm
  798. externCP macro n,c
  799. externW <n>,c
  800. endm
  801. endif
  802. if sized
  803. externDP macro n,c
  804. externD <n>,c
  805. endm
  806. else
  807. externDP macro n,c
  808. externW <n>,c
  809. endm
  810. endif
  811. ??CM_ex1 macro names, langType, kind
  812. setDefLangType langType
  813. for name,<names>
  814. ifidn defLangType,<C>
  815. name textequ ??CM_Paste(_, name)
  816. extern ??CM_Paste(_, name):kind
  817. else
  818. extern defLangType name:kind
  819. endif
  820. endm
  821. endm
  822. endif ; ?NOEXTERN
  823. ifndef ?NOLABEL
  824. ; labelX - define label of data type X
  825. ;
  826. labelB macro names:req,langType
  827. ??CM_lb1 <names>, langType, BYTE
  828. endm
  829. labelW macro names:req,langType
  830. ??CM_lb1 <names>, langType, WORD
  831. endm
  832. labelD macro names:req,langType
  833. ??CM_lb1 <names>, langType, DWORD
  834. endm
  835. labelQ macro names:req,langType
  836. ??CM_lb1 <names>, langType, QWORD
  837. endm
  838. labelT macro names:req,langType
  839. ??CM_lb1 <names>, langType, TBYTE
  840. endm
  841. labelNP macro names:req,langType
  842. ??CM_lb1 <names>, langType, NEAR
  843. endm
  844. labelFP macro names:req,langType
  845. ??CM_lb1 <names>, langType, FAR
  846. endm
  847. if sizec
  848. labelP macro n,c
  849. labelFP <n>,c
  850. endm
  851. labelCP macro n,c
  852. labelD <n>,c
  853. endm
  854. else
  855. labelP macro n,c
  856. labelNP <n>,c
  857. endm
  858. labelCP macro n,c
  859. labelW <n>,c
  860. endm
  861. endif
  862. if sized
  863. labelDP macro n,c
  864. labelD <n>,c
  865. endm
  866. else
  867. labelDP macro n,c
  868. labelW <n>,c
  869. endm
  870. endif
  871. ??CM_lb1 macro names:req, langType, kind
  872. setDefLangType langType
  873. ?pu = 0
  874. for name,<names>
  875. ifidn <name>,<PUBLIC>
  876. ?pu =1
  877. else
  878. ifidn defLangType,<C>
  879. if ?pu
  880. public ??CM_Paste(_, name)
  881. endif
  882. name textequ ??CM_Paste(_, name)
  883. ??CM_Paste(_, name) label kind
  884. else
  885. if ?pu
  886. public name
  887. endif
  888. name label kind
  889. endif
  890. endif
  891. endm
  892. endm
  893. endif ; ?NOLABEL
  894. ifndef ?NODEF
  895. ; defX - inform the macros that name is of type X
  896. ;
  897. ; The given name(s) is flagged to be of the given type.
  898. ;
  899. ; This macro is no longer needed.
  900. ;
  901. for lbl,<defB, defW, defD, defQ, defT, defCP, defDP>
  902. lbl macro names:req
  903. endm
  904. endm
  905. endif ; ?NODEF
  906. ifndef ?NOPTR
  907. ;; regPtr generates information allowing a 32-bit pointer currently
  908. ;; in a register to be pushed as a parameter to a subroutine using
  909. ;; the cCall macro.
  910. ;;
  911. ;; usage:
  912. ;; regptr n,s,o
  913. ;; where:
  914. ;; n is the name the argument will be known as
  915. ;; s is the register containing the segment portion
  916. ;; of the pointer
  917. ;; o is the register containing the offset portion
  918. ;; of the pointer
  919. ;;
  920. ;; 2/14/85 - made obsolete with farptr
  921. regPtr macro n,s,o
  922. farPtr n,s,o
  923. endm
  924. ;; farPtr generates information allowing a 32-bit pointer to be
  925. ;; pushed as a parameter to a subroutine using the cCall macro.
  926. ;;
  927. ;; usage:
  928. ;; farptr n,s,o
  929. ;; where:
  930. ;; n is the name the argument will be known as
  931. ;; s is the segment portion of the pointer
  932. ;; o is the offset portion of the pointer
  933. ;;
  934. ;; Note that any cast must have been made in the argument itself
  935. ;; (i.e. regptr ptr1,ds,<word ptr 3[si]>)
  936. farPtr macro n,s,o
  937. n macro
  938. push s
  939. push o
  940. endm
  941. endm
  942. endif ; ?NOPTR
  943. ;; arg - declare arguements
  944. ;;
  945. ;; The given arguments(s) is added to the argument list structure
  946. ;;
  947. ;; format:
  948. ;; arg a
  949. ;;
  950. ;; where:
  951. ;; a is any valid arugment(s) to push
  952. ;;
  953. ;; If any element in arglist has not been defined or isn't 16-bit
  954. ;; register, then a compilete specification must have been given in
  955. ;; a text equate and a defx also given (if not, you'll pay the penalty!)
  956. ;;
  957. arg macro args
  958. ifnb <args>
  959. ifnb ??CM_ArgList
  960. ??CM_ArgList textequ ??CM_ArgList, <,>, <args>
  961. else
  962. ??CM_ArgList textequ <args>
  963. endif
  964. endif
  965. endm
  966. ;; ?CM_IsIdent - is the arguement a legal identifier?
  967. ;;
  968. ;;
  969. ;; Need to enforce the following additional rules:
  970. ;; Digit may not be first character
  971. ;; Assorted other characters may be used
  972. ;; Dot may be the first character
  973. ?CM_IsIdent macro name:REQ
  974. LOCAL result
  975. result = 1
  976. forc char,<name>
  977. if ('A' LE '&char') AND ('&char' LE 'Z')
  978. goto next
  979. endif
  980. if ('a' LE '&char') AND ('&char' LE 'z')
  981. goto next
  982. endif
  983. if ('0' LE '&char') AND ('&char' LE '9')
  984. goto next
  985. endif
  986. result = 0
  987. exitm
  988. :next
  989. endm
  990. exitm %result
  991. endm
  992. ;; @reverse
  993. ;;
  994. @reverse macro list
  995. LOCAL newlist
  996. newlist textequ <>
  997. for x,<list>
  998. newlist catstr <x>, <,>, newlist
  999. endm
  1000. ifnb newlist
  1001. newlist substr newlist, 1, @sizestr(%newlist)-1
  1002. endif
  1003. exitm newlist
  1004. endm
  1005. ;; ?ap - process arguments and place onto stack
  1006. ;;
  1007. ;; The given argument is processed (type checking) and placed
  1008. ;; on the stack for a pending call. There must be a type
  1009. ;; definition for all arguments (except words). This can be
  1010. ;; done using text equates and the defx macro.
  1011. ;;
  1012. ?ap macro n
  1013. ?argl=?argl+2 ;; assume one word is pushed
  1014. if 0 EQ (OPATTR n)
  1015. if ?CM_IsIdent(n)
  1016. ifdef n
  1017. n
  1018. exitm
  1019. endif
  1020. endif
  1021. % .err <'&n' is not valid to push>
  1022. exitm
  1023. else
  1024. i = (TYPE n)
  1025. if i EQ 1 ;; byte type
  1026. push word ptr(n)
  1027. exitm
  1028. endif
  1029. if i EQ 2 ;; word type
  1030. push n
  1031. exitm
  1032. endif
  1033. if i EQ 4 ;; dword type
  1034. push word ptr (n)[2]
  1035. push word ptr (n)
  1036. ?argl=?argl+2
  1037. exitm
  1038. endif
  1039. if i EQ 8 ;; qword type
  1040. push word ptr (n)[6]
  1041. push word ptr (n)[4]
  1042. push word ptr (n)[2]
  1043. push word ptr (n)
  1044. ?argl=?argl+6
  1045. exitm
  1046. endif
  1047. push word ptr (n) ;; variable storage
  1048. exitm
  1049. endif
  1050. endm
  1051. ;; cCall - call a 'c' language procedure
  1052. ;;
  1053. ;; The given procedure is called with the given parameters. If the
  1054. ;; calling convention is C, the arguments are pushed in reverse order,
  1055. ;; and removed after the called procedure returns. If the calling
  1056. ;; convention is PL/M, the arguments are pushed as they were encountered,
  1057. ;; and the called procedure is assumed to have removed them
  1058. ;; from the stack.
  1059. ;;
  1060. ;; The calling convention priority will be:
  1061. ;; 1) that specified on the cCall if present,
  1062. ;; 2) that defined by the target,
  1063. ;; 3) the default (?PLM flag).
  1064. ;;
  1065. ;; format:
  1066. ;; cCall n,<a>,c
  1067. ;;
  1068. ;; where:
  1069. ;; n is the name of the procedure to call
  1070. ;; a are the arguments to be pushed (optional, may be specified
  1071. ;; with the "arg" macro.
  1072. ;; c is the calling convention, C for C, PLM or PASCAL for
  1073. ;; PL/M. The default (?PLM flag) will be used if
  1074. ;; not specified).
  1075. ;;
  1076. cCall macro name:req,args,langType
  1077. ifnb <args> ;; add any passed in arguments
  1078. arg <args> ;; to the list of arguments
  1079. endif ;; for this procedure
  1080. ifnb ??CM_RegSaveList ;; If there are any resgisters
  1081. % for reg,<??CM_RegSaveList> ;; to be saved across the call
  1082. push reg ;; save then on the stack
  1083. endm ;;
  1084. endif ;;
  1085. ifnb <langType> ;; If a lang type was specified then
  1086. setDefLangType langType ;; it overrides all common sense
  1087. else
  1088. i = ((OPATTR name) SHR 8) AND 7 ;; Get the lang type from the symbol
  1089. if i EQ 0 ;; No lang type ---
  1090. setDefLangType ;; Use the default lang type
  1091. elseif i EQ 1 ;; C lang type
  1092. defLangType textequ <C> ;;
  1093. elseif i EQ 4 ;; Pascal Lang Type
  1094. defLangType textequ <PASCAL> ;;
  1095. else ;; Unknown lang type
  1096. .err <Unknown lang type specfied for '&name'> ;;
  1097. endif
  1098. endif
  1099. ifidn defLangType,<C> ;; If using C calling convention
  1100. ??CM_ArgList textequ @reverse(%??CM_ArgList) ;; then reverse the arguements
  1101. endif ;;
  1102. ?argl=0 ;; Clear arguement byte count
  1103. % for arg,<??CM_ArgList> ;; Push the procedures arguements
  1104. ?ap <arg> ;; onto the stack. ?ap takes
  1105. endm ;; care of sizing arguements
  1106. call name ;; Do the actual call
  1107. ifidn defLangType,<C> ;; If this is a C proc and there
  1108. if ?argl NE 0 ;;
  1109. add sp,?argl ;; are parameters then pop them
  1110. endif ;; off the stack
  1111. endif ;;
  1112. ifnb ??CM_RegSaveList ;; If there were any saved registers
  1113. ??CM_RegSaveList textequ @reverse(%??CM_RegSaveList) ;; then pop them off the stack
  1114. % for reg,<??CM_RegSaveList> ;; at this point.
  1115. pop reg ;;
  1116. endm ;;
  1117. endif ;;
  1118. ??CM_RegSaveList textequ <> ;; Clear out the global state
  1119. ??CM_ArgList textequ <> ;; variable used by the cCall macro
  1120. endm
  1121. ;; save - flag that the indicated registers are to be saved/restored
  1122. ;; on the next cCall invocation
  1123. ;;
  1124. ;; usage:
  1125. ;; save <r>
  1126. ;;
  1127. ;; where:
  1128. ;; r is the list of registers to be saved.
  1129. ;;
  1130. ;; the macro generates a value for the variable ??CM_RegSaveList
  1131. ;;
  1132. save macro r
  1133. ??CM_RegSaveList textequ <r>
  1134. endm
  1135. ;; parmX - generate reference to parameter(s) on the stack
  1136. ;;
  1137. ;; usage:
  1138. ;; parmX n
  1139. ;; where:
  1140. ;; x is the type of the argument(s) b=byte, w=word, d=dword
  1141. ;; n is the name(s) to be given the parmeter(s).
  1142. ;;
  1143. ;; Byte are considered to be two bytes long for alignment.
  1144. ;;
  1145. ;; The parmd form of the macro generates two equates:
  1146. ;;
  1147. ;; off_name - for accessing the offset (lsw) of the parameter
  1148. ;; seg_name - for accessing the segment (msw) of the parameter
  1149. ;;
  1150. parmB macro names:req
  1151. for name,<names>
  1152. ??CM_addParm <&name:BYTE>
  1153. endm
  1154. endm
  1155. parmW macro names:req
  1156. for name,<names>
  1157. ??CM_addParm <&name:WORD>
  1158. endm
  1159. endm
  1160. parmD macro names:req
  1161. for name,<names>
  1162. ??CM_addParm <&name:DWORD>
  1163. ??CM_Paste(off_, name) textequ <word ptr name[0]>
  1164. ??CM_Paste(seg_, name) textequ <word ptr name[2]>
  1165. endm
  1166. endm
  1167. parmQ macro names:req
  1168. for name,<names>
  1169. ??CM_addParm <&name:QWORD>
  1170. endm
  1171. endm
  1172. parmT macro names:req
  1173. for name,<names>
  1174. ??CM_addParm <&name:TBYTE>
  1175. endm
  1176. endm
  1177. if sizec
  1178. parmCP macro n
  1179. parmD <n>
  1180. endm
  1181. else
  1182. parmCP macro n
  1183. parmW <n>
  1184. endm
  1185. endif
  1186. if sized
  1187. parmDP macro n
  1188. parmD <n>
  1189. endm
  1190. else
  1191. parmDP macro n
  1192. parmW <n>
  1193. endm
  1194. endif
  1195. if 0
  1196. ;; parmR - register parameter
  1197. ;;
  1198. ;; parmR is the macro used for generating register parameters.
  1199. ;; The space allocated for the register parameters will be
  1200. ;; the ?ia (interface adjust) area which is between the old
  1201. ;; BP and the first parameter. Normally this is empty (?ia=0),
  1202. ;; or has the saved ds for a windows far procedure.
  1203. ;;
  1204. ;; Byte and dword register parameters will be allowed.
  1205. ;;
  1206. ;; usage:
  1207. ;; parmR n,r,r2
  1208. ;; where:
  1209. ;; n is the name of the parameter
  1210. ;; r is the register it is in
  1211. ;; r2 is the offset register if a dword
  1212. ifndef ?NOPARMR
  1213. .xcref
  1214. .xcref ?pr,parmR
  1215. .cref
  1216. parmR macro n,r,r2
  1217. ?pr n,r,r2,%?rp,%(?ia+2)
  1218. endm
  1219. ;; ?pr - register parameter
  1220. ;;
  1221. ;; ?pr is the actual macro for generating the equates for
  1222. ;; register parameters.
  1223. ;;
  1224. ;; usage:
  1225. ;; parmR n,r,r2,i,o
  1226. ;; where:
  1227. ;; n is the name of the parameter
  1228. ;; r is the register it is in
  1229. ;; r2 is the offset register if a dword
  1230. ;; i is the index of the ?rp to generate
  1231. ;; o is the offset from bp where the parm will be
  1232. ?pr macro n,r,r2,i,o
  1233. .xcref
  1234. ifnb <r2> ;;if a dword parameter
  1235. parmR seg_&n,r ;;define segment equate
  1236. parmR off_&n,r2 ;;define offset equate
  1237. n equ (dword ptr [bp-o-2]) ;;define dword equate
  1238. .xcref ?t&n
  1239. ?t&n=4 ;;show a dword to cmacros
  1240. else
  1241. .xcref ?rp&i
  1242. ?rp&i=0 ;;show no register(s)
  1243. ifdef ?&r ;;define register if valid
  1244. ?rp&i=?&r
  1245. endif
  1246. if ??? or (?cpd eq 0) or (?rp&i eq 0)
  1247. ??error <invalid parmR encountered: &n,&r>
  1248. exitm
  1249. endif
  1250. n equ (word ptr [bp-o]) ;;assume a word register
  1251. ?t&n=2 ;;show a word to cmacros
  1252. irp x,<bh,ch,dh,bl,cl,dl,ah,al>
  1253. if ?&&x eq ?&r ;;if really a byte register
  1254. n equ (byte ptr [bp-o]) ;; then make it a byte
  1255. ?t&n=1 ;;show a byte to cmacros
  1256. exitm
  1257. endif
  1258. endm
  1259. ?ia=?ia+2 ;;show this guy is out there
  1260. ?rp=?rp+1 ;;show one more register parameter
  1261. endif
  1262. .cref
  1263. endm
  1264. endif
  1265. endif
  1266. localB macro name
  1267. ??CM_addLocal ??CM_Paste(name, <:BYTE>)
  1268. endm
  1269. localW macro name
  1270. ??CM_addLocal ??CM_Paste(name, <:WORD>)
  1271. endm
  1272. localD macro name
  1273. ??CM_addLocal ??CM_Paste(name, <:DWORD>)
  1274. off_&name textequ <word ptr name[0]>
  1275. seg_&name textequ <word ptr name[2]>
  1276. endm
  1277. localQ macro name
  1278. ??CM_addLocal ??CM_Paste(name, <:QWORD>)
  1279. endm
  1280. localT macro name
  1281. ??CM_addLocal ??CM_Paste(name, <:TBYTE>)
  1282. endm
  1283. if sizec
  1284. localCP macro n
  1285. localD <n>
  1286. endm
  1287. else
  1288. localCP macro n
  1289. localW <n>
  1290. endm
  1291. endif
  1292. if sized
  1293. localDP macro n
  1294. localD <n>
  1295. endm
  1296. else
  1297. localDP macro n
  1298. localW <n>
  1299. endm
  1300. endif
  1301. localV macro name,a
  1302. local t1
  1303. t1 catstr <name>, < [>, %a, <]:BYTE>
  1304. % ??CM_addLocal <t1>
  1305. endm
  1306. ife ?DF
  1307. ;;
  1308. ;; Define all segments that will be used. This will allow the
  1309. ;; assume and groups to be set up at one given place, and also
  1310. ;; allow quick changes to be made
  1311. ;;
  1312. createSeg _TEXT,Code,word,public,CODE
  1313. ife ?NODATA
  1314. createSeg _DATA,Data,word,public,DATA,DGROUP
  1315. endif
  1316. endif
  1317. ; errnz exp - generate error message if expression isn't zero
  1318. ;
  1319. ; The errnz will generate an error message if the expression "exp"
  1320. ; does not evaluate to zero. This macro is very useful for testing
  1321. ; relationships between items, labels, and data that was coded into
  1322. ; an application.
  1323. ;
  1324. ; errnz <offset $ - offset label> ;error if not at "label"
  1325. ; errnz <eofflag and 00000001b> ;eofflag must be bit 0
  1326. ;
  1327. ; For expressions involving more than one token, the angle brackets
  1328. ; must be used.
  1329. ;
  1330. ; The macro is only evaluated on pass 2, so forward references may be
  1331. ; used in the expression.
  1332. errnz macro x ;;display error if expression is <>0
  1333. .errnz x
  1334. endm
  1335. ; errn$ label,exp - generate error message if label (exp) <> $
  1336. ;
  1337. ; The errnz will generate an error message if the label and "exp"
  1338. ; does not evaluate to the current value of the location counter.
  1339. ; This macro is very useful for testing relationships between
  1340. ; labels and the location counter that was coded into an application.
  1341. ;
  1342. ; examples: errn$ label ;error if not at "label"
  1343. ; errn$ label,+3 ;error if not three bytes from "label"
  1344. ; errn$ label,-3 ;error if not three bytes past "label"
  1345. ;
  1346. ; If no "exp" is given, it is the same as specifying 0
  1347. ;
  1348. ; The macro is only evaluated on pass 2, so forward references may be
  1349. ; used in the expression.
  1350. errn$ macro l,x ;;error if <$-label1 (exp2)> <>0
  1351. errnz <offset $ - offset l x>
  1352. endm
  1353. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1354. ; Extra macros for the c-runtime package
  1355. ;
  1356. ; Macro for calling another run-time-library function.
  1357. ; Does a PUSH CS/CALL NEAR in compact/large models, except
  1358. ; for QuickC. --PHG, 5-24-89
  1359. callcrt MACRO funcname
  1360. ifdef _QC2
  1361. call funcname
  1362. else
  1363. if sizeC
  1364. push cs
  1365. call near ptr (funcname)
  1366. else
  1367. call funcname
  1368. endif
  1369. endif
  1370. ENDM
  1371. .cref ; Permit symbols to be listed again