SPAWN.A 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661
  1. (* Release 3.10 *)
  2. (*-------------------------------------------------------------------------*
  3. * *
  4. * SPAWN.A - child process spawning *
  5. * *
  6. * COPYRIGHT (C) 1989..1992 Clarion Software Corporation. *
  7. * All Rights Reserved *
  8. * *
  9. *--------------------------------------------------------------------------*)
  10. include "corelib.inc"
  11. module SPAWN
  12. (*%F _OS2 *)
  13. (****************************************************************************)
  14. section
  15. segment _TEXT(CODE,28H)
  16. segment _DATA(DATA, 28H)
  17. extrn Str$RCharPos
  18. extrn Str$Length
  19. select _TEXT
  20. public __CatProg :
  21. ptr = sframe
  22. temp = -4
  23. locals = 4
  24. push bp
  25. mov bp, sp
  26. sub sp, locals
  27. les bx, [bp][ptr]
  28. (*%F NearPtr *)
  29. mov dx, '\'
  30. mov cx, es:[bx][2]
  31. mov bx, es:[bx]
  32. mov ax, 128
  33. (*%E *)
  34. (*%T NearPtr *)
  35. mov cx, '\'
  36. mov bx, es:[bx]
  37. mov ax, 128
  38. (*%E *)
  39. (*%F RegParam *)
  40. (*%F NearPtr *)
  41. push ax
  42. push cx
  43. push bx
  44. push dx
  45. (*%E *)
  46. (*%T NearPtr *)
  47. push ax
  48. push bx
  49. push cx
  50. (*%E *)
  51. (*%E *)
  52. (*%F NearCall *)
  53. call far Str$RCharPos
  54. (*%E *)
  55. (*%T NearCall *)
  56. call Str$RCharPos
  57. (*%E *)
  58. cmp ax, -1
  59. pushf
  60. add ax, [bp][ptr]
  61. mov dx, [bp][ptr][2]
  62. popf
  63. jnz getLength
  64. les bx, [bp][ptr]
  65. mov ax, es:[bx]
  66. (*%F NearPtr *)
  67. mov dx, es:[bx][2]
  68. (*%E *)
  69. getLength:
  70. mov [bp][temp], ax
  71. (*%F NearPtr *)
  72. mov [bp][temp][2], dx
  73. mov bx, dx
  74. (*%E *)
  75. (*%T NearPtr *)
  76. mov [bp][temp][2], ds
  77. (*%E *)
  78. (*%F NearPtr *)
  79. mov cx, bx
  80. (*%E *)
  81. mov bx, ax
  82. mov ax, 128
  83. (*%F RegParam *)
  84. (*%T NearPtr *)
  85. push ax
  86. push bx
  87. (*%E *)
  88. (*%F NearPtr *)
  89. push ax
  90. push cx
  91. push bx
  92. (*%E *)
  93. (*%E *)
  94. (*%F NearCall *)
  95. call far Str$Length
  96. (*%E *)
  97. (*%T NearCall *)
  98. call Str$Length
  99. (*%E *)
  100. mov cx, ax
  101. mov ax, [bp][temp]
  102. mov dx, [bp][temp][2]
  103. mov sp, bp
  104. pop bp
  105. ret 0
  106. (*****************************************************************************)
  107. section
  108. segment _TEXT(CODE,28H)
  109. segment _DATA(DATA, 28H)
  110. SEARCH = 80H
  111. extrn Str$Length
  112. extrn Lib$EnvironmentFind
  113. select _DATA
  114. extrn __seterrno
  115. PATH : db 'PATH', 0
  116. select _TEXT
  117. public __FindProg :
  118. (*
  119. char *FindProg (usePath, nameP);
  120. boolean usePath;
  121. char *nameP;
  122. The given file name *nameP is to be interpreted as the name of an
  123. executable file, given the usual MSDOS rules for program names:
  124. - if the name ends in ".*" or "." then no endings are substituted,
  125. otherwise the endings ".COM" and ".EXE" will be the trial endings.
  126. - if the name begins with "/" or "\" or "?:", or if the usePath
  127. argument is false, then there are no trial prefixes, else the trial
  128. prefixes are those in the PATH variable in the environment.
  129. - with each prefix, beginning with a null prefix, the name is searched
  130. for using each of its trial endings, continuing until the first
  131. match or until all prefixes and endings have been tried.
  132. A buffer is allocated for the trial paths. If a trial match succeeds,
  133. the result of the function is a pointer to the buffer which holds the
  134. complete path. The file is not open (the CHMOD function is used to
  135. test if the file exists, not FIND). The caller is responsible to free()
  136. the buffer when it is no longer needed.
  137. The function result is a pointer to the buffer. If the search fails
  138. then the buffer is de-allocated and the function result is NULL.
  139. The function also returns the size of the path in CX, with a value of
  140. zero if the search failed.
  141. In the case where a path is found the caller is responsible for
  142. deallocating the buffer, using free().
  143. *)
  144. fpr_bufP = sframe
  145. fpr_usePath = 4+sframe
  146. fpr_nameP = 6+sframe
  147. fpr_preP = -4
  148. fpr_suffix = -6
  149. fpr_len = -8
  150. fpr_res = -10
  151. PathStr = -142
  152. locals = 142
  153. push bp
  154. mov bp, sp
  155. sub sp, locals
  156. push di
  157. push si
  158. push ds
  159. push es
  160. les si, [bp][fpr_nameP]
  161. (*%F RegParam *)
  162. mov ax, 128
  163. push ax
  164. (*%F NearPtr *)
  165. push es
  166. (*%E *)
  167. push si
  168. (*%E *)
  169. (*%T RegParam *)
  170. mov ax, 128
  171. mov cx, es
  172. mov bx, si
  173. (*%E *)
  174. (*%F NearCall *)
  175. call far Str$Length
  176. (*%E *)
  177. (*%T NearCall *)
  178. call Str$Length
  179. (*%E *)
  180. xchg cx, ax (* CX is length of supplied name *)
  181. or cx, cx
  182. jnz fpr_hasName
  183. mov ax, ENOENT
  184. (*%F NearCall *)
  185. call far __seterrno
  186. (*%E *)
  187. (*%T NearCall *)
  188. call __seterrno
  189. (*%E *)
  190. jmp near fpr_badEnd
  191. fpr_hasName:
  192. mov [bp][fpr_len], cx (* keep a copy of the string length *)
  193. mov es, [bp][fpr_nameP][2]
  194. add si, cx (* ES:[si] point to end of string *)
  195. dec si
  196. std (* scan backwards *)
  197. (* Does the name already have a specific ".*" ending ?
  198. If the name ends in ".*" or "." then no endings are substituted.
  199. *)
  200. mov word [bp][fpr_suffix], FALSE (* default is a fixed ending. *)
  201. fpr_checkEnding:
  202. mov al, es:[si]
  203. dec si
  204. cmp al, '.'
  205. je fpr_checkPrefix
  206. cmp al, '/'
  207. je fpr_useSuffixes
  208. cmp al, '\'
  209. je fpr_useSuffixes
  210. loop fpr_checkEnding
  211. (* The endings ".COM" and ".EXE" will be the trial endings.*)
  212. fpr_useSuffixes:
  213. mov word [bp][fpr_suffix], TRUE (* enable trial endings *)
  214. (* If the name begins with "/" or "\" or "?:" or if usePath == false
  215. then there are no trial prefixes, else the trial prefixes are those
  216. in the PATH= variable in the environment.
  217. *)
  218. fpr_checkPrefix:
  219. cld (* forward scan *)
  220. cmp word [bp][fpr_usePath], FALSE
  221. je fpr_allocBuf
  222. mov word [bp][fpr_usePath], FALSE (* default is no prefixes *)
  223. mov cx, [bp][fpr_len]
  224. mov si, [bp][fpr_nameP]
  225. mov al, es:[si]
  226. inc si
  227. cmp al, '/'
  228. je fpr_allocBuf
  229. cmp al, '\'
  230. je fpr_allocBuf
  231. cmp al, ':'
  232. je fpr_allocBuf
  233. (* Prefixes are possible. Look to see if the PATH environment variable
  234. is defined.
  235. *)
  236. (*%F RegParam *)
  237. (*%F NearPtr *)
  238. mov ax, 4
  239. push ax
  240. mov ax, PATH
  241. push ds
  242. push ax
  243. mov ax, 128
  244. push ax
  245. lea ax, [bp][PathStr]
  246. push ss
  247. push ax
  248. (*%E *)
  249. (*%T NearPtr *)
  250. mov ax, 4
  251. push ax
  252. mov ax, PATH
  253. push ax
  254. mov ax, 128
  255. push ax
  256. lea ax, [bp][PathStr]
  257. push ax
  258. (*%E *)
  259. (*%E *)
  260. (*%T RegParam *)
  261. (*%F NearPtr *)
  262. lea ax, [bp][PathStr]
  263. push ss
  264. push ax
  265. mov ax, 4
  266. mov bx, PATH
  267. mov cx, ds
  268. mov dx, 128
  269. (*%E *)
  270. (*%T NearPtr *)
  271. mov ax, 4
  272. mov bx, PATH
  273. mov cx, 128
  274. lea dx, [bp][PathStr]
  275. (*%E *)
  276. (*%E *)
  277. (*%F NearCall *)
  278. call far Lib$EnvironmentFind
  279. (*%E *)
  280. (*%T NearCall *)
  281. call Lib$EnvironmentFind
  282. (*%E *)
  283. lea ax, [bp][PathStr]
  284. cmp byte [bp][PathStr], 0
  285. jz fpr_allocBuf
  286. mov [bp][fpr_preP][2], ss
  287. mov [bp][fpr_preP], ax
  288. mov word [bp][fpr_usePath], SEARCH (* enable prefixes. *)
  289. (* buffer is allocated to hold the complete trial pathnames *)
  290. fpr_allocBuf:
  291. (* With each prefix, beginning with a null prefix, the name is searched
  292. for using each of its trial endings, continuing until the first
  293. match or until all prefixes and endings have been tried.
  294. *)
  295. mov dx, [bp][fpr_bufP][2]
  296. mov ax, [bp][fpr_bufP]
  297. mov es, dx
  298. xchg di, ax
  299. sub bx, bx (* bx counts length of pathname. *)
  300. fpr_copyName:
  301. mov cx, [bp][fpr_len]
  302. add bx, cx
  303. cmp bx, 64
  304. jnb fpr_nextPrefix
  305. lds si, [bp][fpr_nameP]
  306. rep ; movsb
  307. cmp word [bp][fpr_suffix], FALSE (* are suffixes allowed ? *)
  308. je fpr_nameFormed
  309. add bl, 4
  310. cmp bl, 64
  311. jnb fpr_nextPrefix
  312. mov ax, 432EH
  313. stosw (* '.C' *)
  314. mov ax, 4D4FH
  315. stosw (* 'OM'*)
  316. fpr_nameFormed:
  317. lds dx, [bp][fpr_bufP]
  318. mov byte [di], 0
  319. mov ax, 4300H (* Read File's Attributes *)
  320. extrn @DosInterrupt
  321. (*%F NearCall *)
  322. call far @DosInterrupt
  323. (*%E *)
  324. (*%T NearCall *)
  325. call @DosInterrupt
  326. (*%E *)
  327. jc fpr_tryEXE
  328. test cl, 18H (* Avoid subdir or label attributes. *)
  329. jz near fpr_found
  330. fpr_tryEXE:
  331. cmp word [bp][fpr_suffix], FALSE (* are suffixes allowed ? *)
  332. je fpr_nextPrefix (* jump if not allowed. *)
  333. mov word [di][-4], 452EH (* '.E' *)
  334. mov word [di][-2], 4558H (* 'XE' *)
  335. mov ax, 4300H (* Read File's Attributes *)
  336. extrn @DosInterrupt
  337. (*%F NearCall *)
  338. call far @DosInterrupt
  339. (*%E *)
  340. (*%T NearCall *)
  341. call @DosInterrupt
  342. (*%E *)
  343. jc fpr_nextPrefix
  344. test cl, 18H (* Avoid subdir or label attributes. *)
  345. jz fpr_found
  346. (* The prefixes in the PATH variable are of the form "abc;" where abc
  347. represents any string and ';' is a separator. The string may
  348. also be bounded by \0, the terminator for the whole path sequence.
  349. When there is no prefix remaining in PATH, then the search is
  350. finished.
  351. *)
  352. fpr_nextPrefix:
  353. cmp word [bp][fpr_usePath], FALSE (* are prefixes allowed ? *)
  354. je fpr_notFound
  355. lds si, [bp][fpr_preP] (* copy the next path prefix *)
  356. sub bx, bx
  357. mov cx, 60
  358. les di, [bp][fpr_bufP] (* into the working buffer. *)
  359. fpr_scanPrefix:
  360. lodsb
  361. cmp al, ';'
  362. je fpr_preSeparator
  363. cmp al, 0
  364. je fpr_preTerminator
  365. stosb
  366. inc bx
  367. loop fpr_scanPrefix
  368. jmp fpr_notFound (* give up if PATH is badly formed. *)
  369. fpr_preTerminator:
  370. dec si (* the terminator cannot be passed. *)
  371. fpr_preSeparator:
  372. mov [bp][fpr_preP], si (* remember where the PATH continues. *)
  373. or bx, bx (* was that the end of the PATH ? *)
  374. jz fpr_notFound
  375. mov al, es:[di][-1] (* may need to insert '\' *)
  376. cmp al, '\'
  377. je fpr_joinable
  378. cmp al, ':'
  379. je fpr_joinable
  380. cmp al, '/'
  381. je fpr_joinable
  382. mov al, '\'
  383. stosb
  384. inc bx
  385. fpr_joinable:
  386. jmp fpr_copyName (* join name to trial path *)
  387. (* If not found, then de-allocate the name buffer. *)
  388. fpr_notFound:
  389. mov ax, ENOENT
  390. (*%F NearCall *)
  391. call far __seterrno
  392. (*%E *)
  393. (*%T NearCall *)
  394. call __seterrno
  395. (*%E *)
  396. fpr_allocFailed:
  397. fpr_badEnd:
  398. sub ax, ax
  399. cwd
  400. mov cx, ax
  401. jmp fpr_end
  402. fpr_found:
  403. mov ax, dx
  404. mov dx, ds
  405. mov cx, _DATA (* DX:AX points to the name *)
  406. mov ds, cx
  407. mov cx, di
  408. inc cx (* include the terminating zero *)
  409. sub cx, ax (* CX = length of name *)
  410. fpr_end:
  411. pop es
  412. pop ds
  413. pop si
  414. pop di
  415. mov sp, bp
  416. pop bp
  417. ret 0
  418. (*****************************************************************************)
  419. section
  420. segment _TEXT(CODE,28H)
  421. segment _DATA(DATA, 28H)
  422. extrn Str$Length
  423. extrn __seterrno
  424. select _TEXT
  425. extrn Str$Length
  426. public __CatArgV :
  427. (*
  428. char *_CatArgV (argV)
  429. char *argV [];
  430. Take the vector of arguments and concatenate them into an MSDOS-style
  431. command line. Use a space to separate each argument, with a maximu of
  432. 126 characters, plus a preceding length byte and a following CR ('0x0D').
  433. Also, check the assumption that *argV[1] and *argV[2] may be MSDOS 1.xx
  434. style (CPM-era) file names. If so, construct FCBs from them.
  435. A NULL entry in the argV vector is taken as a terminator. The entry
  436. argV[0] by Unix convention is a command name which should not appear in
  437. the MSDOS command line, so it is entirely ignored here.
  438. Allocate a structure to hold the two FCBs and the command line. If the
  439. command line does not overflow, then the return value is the pointer to
  440. the structure:
  441. argComposite
  442. FCB1 char [16];
  443. FCB2 char [16];
  444. length char;
  445. text char [127]; /* includes trailing 0x0D */
  446. The size of the arguments is calculated. If it will total more than
  447. 126 bytes, including spaces, then the function quits without allocating
  448. an argComposite. If the total is OK, then the size of argComposite is
  449. trimmed to hold just the necessary number of characters.
  450. The return value is a pointer to the argComposite, in DX:AX, with the
  451. total length of the argComposite in CX. If an error occurs, then
  452. DX:AX == NULL and CX == 0.
  453. *)
  454. cav_bufP = sframe
  455. cav_argV = 4+sframe
  456. locals = 4
  457. push bp
  458. mov bp, sp
  459. sub sp, locals
  460. push di
  461. push si
  462. push ds
  463. push es
  464. sub di, di (* DI = total length of arguments *)
  465. lds si, [bp][cav_argV]
  466. mov ax, ds
  467. or ax, si
  468. jz cav_argVnull (* NULL argV is allowed, arg total == 0 *)
  469. cav_measureNext: (* note: argV[0] deliberately skipped *)
  470. (*%F NearPtr *)
  471. add si, 4
  472. les bx, [si]
  473. mov ax, es
  474. or ax, bx
  475. (*%E *)
  476. (*%T NearPtr *)
  477. add si, 2
  478. mov bx, [si]
  479. or bx, bx
  480. (*%E *)
  481. jz cav_allMeasured
  482. (*%F RegParam *)
  483. mov ax, 128
  484. push ax
  485. (*%F NearPtr *)
  486. push es
  487. (*%E *)
  488. push bx
  489. (*%E *)
  490. (*%T RegParam *)
  491. mov ax, 128
  492. mov cx, es
  493. (*%E *)
  494. (*%F NearCall *)
  495. call far Str$Length
  496. (*%E *)
  497. (*%T NearCall *)
  498. call Str$Length
  499. (*%E *)
  500. add di, ax
  501. inc di (* plus a separating space or final CR *)
  502. jmp cav_measureNext
  503. cav_argVnull:
  504. inc di (* allow for trailing CR *)
  505. cav_allMeasured:
  506. mov ax, _DATA (* is command line NearPtr enough ? *)
  507. mov ds, ax
  508. cmp di, 127
  509. ja cav_tooLarge
  510. mov dx, [bp][cav_bufP][2]
  511. mov ax, [bp][cav_bufP]
  512. (* Now the composite is allocated. First fill out the FCB headers, using
  513. *argV[1] & [2]. *)
  514. mov es, dx
  515. xchg di, ax
  516. mov word es:[di], 20FFH (* default FCBs *)
  517. mov word es:[di][10H], 20FFH (* are marked as empty. *)
  518. lds si, [bp][cav_argV]
  519. mov ax, ds
  520. or ax, si
  521. jz cav_copyArgs (* no FCBs if argV == NULL *)
  522. (*%F NearPtr *)
  523. lds si, [si][4] (* argV[1] *)
  524. mov ax, ds
  525. or ax, si
  526. (*%E *)
  527. (*%T NearPtr *)
  528. mov si, [si][2] (* argV[1] *)
  529. or si, si
  530. (*%E *)
  531. jz cav_copyArgs
  532. mov ax, 2901H (* parse filename, allow leading spaces *)
  533. extrn @DosInterrupt
  534. (*%F NearCall *)
  535. call far @DosInterrupt
  536. (*%E *)
  537. (*%T NearCall *)
  538. call @DosInterrupt
  539. (*%E *)
  540. add di, 10H (* point to the second FCB *)
  541. lds si, [bp][cav_argV]
  542. (*%F NearPtr *)
  543. lds si, [si][8] (* argV[1] *)
  544. mov ax, ds
  545. or ax, si
  546. (*%E *)
  547. (*%T NearPtr *)
  548. mov si, [si][4] (* argV[1] *)
  549. or si, si
  550. (*%E *)
  551. jz cav_copyArgs
  552. mov ax, 2901H (* parse filename, allow leading spaces *)
  553. extrn @DosInterrupt
  554. (*%F NearCall *)
  555. call far @DosInterrupt
  556. (*%E *)
  557. (*%T NearCall *)
  558. call @DosInterrupt
  559. (*%E *)
  560. cav_copyArgs:
  561. les di, [bp][cav_bufP]
  562. add di, 21H (* begin after the length byte *)
  563. lea cx, [di][-1] (* remember where the length byte is. *)
  564. mov bx, [bp][cav_argV]
  565. cav_nextArg:
  566. (*%F NearPtr *)
  567. mov ds, [bp][cav_argV][2]
  568. mov ax, ds
  569. or ax, bx (* is argV == NULL ? *)
  570. jz cav_terminate
  571. add bx, 4 (* next argument *)
  572. lds si, [bx]
  573. mov ax, ds
  574. or ax, si
  575. jz cav_terminate
  576. (*%E *)
  577. (*%T NearPtr *)
  578. or bx, bx (* is argV == NULL ? *)
  579. jz cav_terminate
  580. add bx, 2 (* next argument *)
  581. mov si, [bx]
  582. or si, si
  583. jz cav_terminate
  584. (*%E *)
  585. mov al, ' ' (* separate the arguments *)
  586. stosb
  587. cav_copyLoop:
  588. lodsb (* copy argument *)
  589. or al, al
  590. jz cav_nextArg
  591. stosb (* to the new command line *)
  592. jmp cav_copyLoop
  593. cav_tooLarge:
  594. mov ax, E2BIG
  595. (*%F NearCall *)
  596. call far __seterrno
  597. (*%E *)
  598. (*%T NearCall *)
  599. call __seterrno
  600. (*%E *)
  601. cav_allocFailed:
  602. sub ax, ax (* return a NULL pointer *)
  603. cwd
  604. mov cx, ax (* and a zero length *)
  605. jmp cav_end
  606. cav_terminate:
  607. mov ax, _DATA
  608. mov ds, ax
  609. mov al, 0DH (* arriage return *)
  610. stosb
  611. xchg di, cx (* DI = &lengthByte, CX = &last byte *)
  612. mov ax, [bp][cav_bufP]
  613. sub cx, ax (* CX = composite length *)
  614. mov bx, cx
  615. sub bl, 22H
  616. mov es:[di], bl (* prefix the command line with length *)
  617. (* The argComposite is now complete. *)
  618. mov dx, es
  619. cav_end:
  620. pop es
  621. pop ds
  622. pop si
  623. pop di
  624. mov sp, bp
  625. pop bp
  626. ret 0
  627. (*****************************************************************************)
  628. section
  629. segment _TEXT(CODE,28H)
  630. segment _DATA(DATA, 28H)
  631. extrn Str$Length
  632. select _DATA
  633. extrn __seterrno
  634. extrn __env_var
  635. select _TEXT
  636. extrn Str$Length
  637. public __CatEnvV :
  638. (*
  639. char *_CatEnvV (envV)
  640. char *envV [];
  641. Take the environment vector and concatenate the environment strings into
  642. an MSDOS-style contiguous environment. Each string remains terminated by
  643. a zero, with a null string as an overall terminator and a maximum length
  644. of 32k bytes.
  645. If a NULL envV value is supplied, then replace it with the global _environ
  646. variable.
  647. The size of the environment is totalled, and if it does not exceed 32k bytes
  648. then a space is allocated, including 15 byte extra for paragraph alignment.
  649. The environment is adjusted to begin on a paragraph boundary since MSDOS
  650. uses segment values alone to locate environment strings.
  651. A NULL entry in the envV vector or a pointer to an empty string are taken
  652. as terminators.
  653. The return value in DX:AX is the pointer to the allocated memory (NULL if
  654. none allocated). The register ES contains the paragraph number at which
  655. the environment string actually begins (zero if none allocated). Note
  656. that while MSDOS needs only the ES value, the DX:AX pointer will in general
  657. be required in order to free() the allocation.
  658. The register CX returns the length of the environment string, including
  659. the terminating zero. CX == 0 in cases of error.
  660. *)
  661. cev_bufP = sframe
  662. cev_envV = 4+sframe
  663. locals = 4
  664. push bp
  665. mov bp, sp
  666. sub sp, locals
  667. push di
  668. push si
  669. push ds
  670. les si, [bp][cev_envV]
  671. (*%F NearPtr *)
  672. mov ax, es
  673. or ax, si
  674. (*%E *)
  675. (*%T NearPtr *)
  676. or si, si (* is a NULL parameter supplied ? *)
  677. (*%E *)
  678. jnz cev_envVset
  679. sub ax, ax
  680. mov es, ax
  681. mov dx, ax
  682. mov cx, 1
  683. jmp near cev_end
  684. cev_envVset:
  685. push es
  686. pop ds
  687. sub di, di (* DI = total length of strings *)
  688. cev_measureNext:
  689. (*%F NearPtr *)
  690. les bx, [si]
  691. add si, 4
  692. mov ax, es
  693. or ax, bx
  694. jz cev_allMeasured
  695. (*%F RegParam *)
  696. mov ax, 128
  697. push ax
  698. (*%F NearPtr *)
  699. push es
  700. (*%E *)
  701. push bx
  702. (*%E *)
  703. (*%T RegParam *)
  704. mov ax, 128
  705. mov cx, es
  706. (*%E *)
  707. (*%F NearCall *)
  708. call far Str$Length
  709. (*%E *)
  710. (*%T NearCall *)
  711. call Str$Length
  712. (*%E *)
  713. or ax, ax
  714. jz cev_allMeasured
  715. add di, ax
  716. inc di (* plus a terminating \0 *)
  717. jmp cev_measureNext
  718. (*%E *)
  719. (*%T NearPtr *)
  720. mov bx, [si]
  721. add si, 2
  722. or bx, bx
  723. jz cev_allMeasured
  724. (*%F RegParam *)
  725. mov ax, 128
  726. push ax
  727. (*%F NearPtr *)
  728. push es
  729. (*%E *)
  730. push bx
  731. (*%E *)
  732. (*%T RegParam *)
  733. mov ax, 128
  734. mov cx, es
  735. (*%E *)
  736. (*%F NearCall *)
  737. call far Str$Length
  738. (*%E *)
  739. (*%T NearCall *)
  740. call Str$Length
  741. (*%E *)
  742. or ax, ax
  743. jz cev_allMeasured
  744. add di, ax
  745. inc di (* plus a terminating \0 *)
  746. jmp cev_measureNext
  747. (*%E *)
  748. cev_allMeasured:
  749. inc di (* plus an overall terminator \0 *)
  750. mov ax, _DATA
  751. mov ds, ax
  752. cmp di, ARG_BUF_SIZE-0FH
  753. ja cev_tooLarge
  754. mov dx, [bp][cev_bufP][2]
  755. mov ax, [bp][cev_bufP]
  756. (* Align the environment on a paragraph boundary. *)
  757. add ax, 15
  758. mov cl, 4
  759. shr ax, cl
  760. add dx, ax
  761. sub ax, ax (* DX:AX is now paragraph aligned *)
  762. (* Now the environment is allocated. Copy the strings into it. *)
  763. mov es, dx
  764. mov di, ax
  765. mov bx, [bp][cev_envV]
  766. cev_nextArg:
  767. (*%F NearPtr *)
  768. mov ds, [bp][cev_envV][2]
  769. lds si, [bx]
  770. add bx, 4 (* next string *)
  771. mov ax, ds
  772. or ax, si
  773. jz cev_terminate
  774. cmp byte [si], 0
  775. je cev_terminate
  776. (*%E *)
  777. (*%T NearPtr *)
  778. mov si, [bx]
  779. add bx, 2 (* next string *)
  780. or si, si
  781. jz cev_terminate
  782. cmp byte [si], 0
  783. je cev_terminate
  784. (*%E *)
  785. cev_copyLoop:
  786. lodsb (* copy string *)
  787. or al, al
  788. stosb (* to the new environment *)
  789. jnz cev_copyLoop
  790. jmp cev_nextArg
  791. cev_tooLarge:
  792. mov ax, E2BIG
  793. (*%F NearCall *)
  794. call far __seterrno
  795. (*%E *)
  796. (*%T NearCall *)
  797. call __seterrno
  798. (*%E *)
  799. cev_allocFailed:
  800. sub ax, ax (* return a NULL pointer *)
  801. cwd
  802. mov cx, ax (* with zero size. *)
  803. jmp cev_end
  804. cev_terminate:
  805. mov ax, _DATA
  806. mov ds, ax
  807. mov al, 0 (* overall terminator zero *)
  808. stosb
  809. (* The environment is now complete. *)
  810. mov cx, di (* CX = size of environment. *)
  811. mov ax, [bp][cev_bufP] (* DX:AX = &allocation block *)
  812. mov dx, [bp][cev_bufP][2] (* ES:0 = &environment. *)
  813. cev_end:
  814. pop ds
  815. pop si
  816. pop di
  817. mov sp, bp
  818. pop bp
  819. ret 0
  820. (*****************************************************************************)
  821. section
  822. segment _TEXT(CODE,28H)
  823. segment _DATA(DATA, 28H)
  824. extrn __shr_mem
  825. extrn __res_mem
  826. extrn __get_retcode
  827. extrn __FindProg
  828. extrn __CatArgV
  829. extrn __CatEnvV
  830. extrn __FloatExecSave
  831. extrn __FloatExecRestore
  832. select _DATA
  833. extrn __seterrno
  834. extrn __fmemsetup
  835. select _TEXT
  836. public __beget :
  837. (*
  838. int _beget (pathP, argV, envV, flag)
  839. char *pathP;
  840. char *argV [];
  841. char *envV [];
  842. int flag
  843. A child process, with program identified by *pathP, is found, validated,
  844. and executed. The current process continues to exist but is asleep
  845. until the child process is finished.
  846. A return value of -1 indicates that the child process could not be
  847. created. Otherwise, the return value will be the exit code of the
  848. child process, which by convention is zero if the child executed
  849. without fault. The exact meaning and severity of non-zero exit
  850. codes are not standardised.
  851. If usePath is true then the PATH environment variable will be used to
  852. help find the program name, otherwise *pathP is assumed to include
  853. directory names and the PATH is not used. However, in either case
  854. the suffixes ".COM" and ".EXE" will automatically be tried unless
  855. the supplied name already ends with an extention.
  856. Method
  857. The basis for the begetting of a child process is the MSDOS Exec command,
  858. function 4Bh request kind 0. However, there are several preliminary actions
  859. required. Firstly the exact and complete program name must be found, which
  860. involves tracing the PATH= environment variable. This is done by the
  861. _FindProg function.
  862. Next the arguments must be scanned and concatenated into a single command
  863. string of up to 126 bytes, plus a length byte and a trailing carriage return.
  864. Arguments [1] and [2] may be file names, and so the MSDOS Parse Filename
  865. function (29h) is used to build matching FCB's if possible. This is done
  866. with the _CatArgV function.
  867. Note that argument [0] is by convention the same as pathP. It is not used
  868. and not checked. The end of the argV vector must be set by placing a NULL
  869. pointer in the final element of the vector.
  870. The envV vector points to a collection of environment strings. These must
  871. also be concatenated into a contiguous region of up to 32k bytes, terminated
  872. with a double zero, which is the form expected by Exec. This is done by the
  873. _CatEnvV function. The envV vector is terminated either by a NULL pointer
  874. or by a pointer to a null string. If envV == NULL then the current program's
  875. environment is used.
  876. When all these things have been done the child program may be executed using
  877. function 4Bh, with the environment, command line, and dummy FCBs supplied as
  878. parameters to function 4Bh. After the child has terminated, function 4Dh is
  879. used to pick up the exit code.
  880. *)
  881. (*%F RegParam *)
  882. RetSize = 0
  883. (*%E *)
  884. (*%T RegParam *)
  885. (*%T NearPtr *)
  886. RetSize = 0
  887. (*%E *)
  888. (*%F NearPtr *)
  889. RetSize = 6
  890. (*%E *)
  891. (*%E *)
  892. (*%F RegParam *)
  893. bgt_pathP = frame
  894. (*%F NearPtr *)
  895. bgt_argV = 4+frame
  896. bgt_envV = 8+frame
  897. bgt_flag = 12+frame
  898. (*%E *)
  899. (*%T NearPtr *)
  900. bgt_argV = 2+frame
  901. bgt_envV = 4+frame
  902. bgt_flag = 6+frame
  903. (*%E *)
  904. bgt_fullP = - 4
  905. bgt_environ = - 8
  906. bgt_params = -22
  907. bgt_result = -24
  908. bgt_ProgBuf = -94
  909. bgt_ArgBuf = -254
  910. bgt_EnvBuf = bgt_ArgBuf-ARG_BUF_SIZE
  911. locals = -bgt_EnvBuf
  912. (*%E *)
  913. (*%T RegParam *)
  914. (*%F NearPtr *)
  915. bgt_envV = 2+frame
  916. bgt_flag = frame
  917. bgt_fullP = - 4
  918. bgt_environ = - 8
  919. bgt_params = -22
  920. bgt_result = -24
  921. bgt_pathP = -28
  922. bgt_argV = -32
  923. bgt_ProgBuf = -102
  924. bgt_ArgBuf = -262
  925. bgt_EnvBuf = bgt_ArgBuf-ARG_BUF_SIZE
  926. locals = -bgt_EnvBuf
  927. (*%E *)
  928. (*%T NearPtr *)
  929. bgt_fullP = - 4
  930. bgt_environ = - 8
  931. bgt_params = -22
  932. bgt_result = -24
  933. bgt_pathP = -26
  934. bgt_argV = -28
  935. bgt_envV = -30
  936. bgt_flag = -32
  937. bgt_ProgBuf = -102
  938. bgt_ArgBuf = -262
  939. bgt_EnvBuf = bgt_ArgBuf-ARG_BUF_SIZE
  940. locals = -bgt_EnvBuf
  941. (*%E *)
  942. (*%E *)
  943. push bp
  944. (*%T StackChecks *)
  945. mov bp, locals+40
  946. (*%F NearCall *)
  947. extrn F$StkChk
  948. call far F$StkChk
  949. (*%E *)
  950. (*%T NearCall *)
  951. extrn N$StkChk
  952. call N$StkChk
  953. (*%E *)
  954. (*%E *)
  955. mov bp, sp
  956. sub sp, locals
  957. call far __FloatExecSave
  958. (*%T RegParam *)
  959. (*%F NearPtr *)
  960. mov [bp][bgt_pathP], ax
  961. mov [bp][bgt_pathP][2], bx
  962. mov [bp][bgt_argV], cx
  963. mov [bp][bgt_argV][2], dx
  964. (*%E *)
  965. (*%T NearPtr *)
  966. mov [bp][bgt_pathP], ax
  967. mov [bp][bgt_argV], bx
  968. mov [bp][bgt_envV], cx
  969. mov [bp][bgt_flag], dx
  970. (*%E *)
  971. (*%E *)
  972. push di
  973. push si
  974. push ds
  975. (*%F SameDS *)
  976. mov ax, seg __fmemsetup
  977. mov ds, ax
  978. (*%E *)
  979. mov word [bp][bgt_result], -1 (* default if Exec can't be done *)
  980. (* The exact and complete program name must be found. *)
  981. (*%F NearPtr *)
  982. push [bp][bgt_pathP][2]
  983. (*%E *)
  984. (*%T NearPtr *)
  985. push ds
  986. (*%E *)
  987. push [bp][bgt_pathP]
  988. push [bp][bgt_flag] (* the usePath flag. *)
  989. push ss
  990. lea ax, [bp][bgt_ProgBuf]
  991. push ax
  992. call __FindProg
  993. add sp, 10
  994. or cx, cx
  995. jnz bgt_progFound
  996. jmp near bgt_notFound
  997. bgt_progFound:
  998. mov [bp][bgt_fullP], ax (*the full path of the program file *)
  999. mov [bp][bgt_fullP][2], dx
  1000. (* The arguments must be scanned and concatenated into a single command
  1001. string of up to 126 bytes, plus a length byte and a trailing CR.
  1002. Args [1] and [2] are used to build matching FCB's if possible.
  1003. *)
  1004. (*%F NearPtr *)
  1005. push [bp][bgt_argV][2]
  1006. (*%E *)
  1007. (*%T NearPtr *)
  1008. push ds
  1009. (*%E *)
  1010. push [bp][bgt_argV]
  1011. push ss
  1012. lea ax, [bp][bgt_ArgBuf]
  1013. push ax
  1014. call __CatArgV (* returns FCB1, FCB2, command line, at DX:AX *)
  1015. add sp, 8
  1016. jcxz bgt_badArgs
  1017. mov [bp][bgt_params][8], dx (* pointer to FCB1 *)
  1018. mov [bp][bgt_params][6], ax
  1019. add ax, 10H
  1020. mov [bp][bgt_params][12], dx (* pointer to FCB2 *)
  1021. mov [bp][bgt_params][10], ax
  1022. add ax, 10H
  1023. mov [bp][bgt_params][4], dx (* pointer to command line *)
  1024. mov [bp][bgt_params][2], ax
  1025. (* The environment strings must also be concatenated into a contiguous region
  1026. of up to 32k bytes, terminated with a double zero.
  1027. *)
  1028. (*%F NearPtr *)
  1029. push [bp][bgt_envV][2]
  1030. (*%E *)
  1031. (*%T NearPtr *)
  1032. push ds
  1033. (*%E *)
  1034. push [bp][bgt_envV]
  1035. push ss
  1036. lea ax, [bp][bgt_EnvBuf]
  1037. push ax
  1038. call __CatEnvV (* returns environment at DX:AX, ES:0 *)
  1039. add sp, 8
  1040. jcxz bgt_badEnv
  1041. mov [bp][bgt_environ], ax
  1042. mov [bp][bgt_environ][2], dx
  1043. mov [bp][bgt_params], es (* paragraph aligned within DX:AX *)
  1044. (* Open a memory space. *)
  1045. mov cx, [__shr_mem]
  1046. sub ax, ax
  1047. (*%F NearCall *)
  1048. or cx, [__shr_mem][2]
  1049. jz dontShrink
  1050. call dword [__shr_mem]
  1051. (*%E *)
  1052. (*%T NearCall *)
  1053. jcxz dontShrink
  1054. call cx
  1055. (*%E *)
  1056. dontShrink:
  1057. (* The child program may be executed using function 4Bh. *)
  1058. push ds
  1059. push ss
  1060. pop es
  1061. lds dx, [bp][bgt_fullP]
  1062. lea bx, [bp][bgt_params]
  1063. mov ax, 4B00H (* Execute (DS:DX using ES:BX) *)
  1064. extrn @DosInterrupt
  1065. (*%F NearCall *)
  1066. call far @DosInterrupt
  1067. (*%E *)
  1068. (*%T NearCall *)
  1069. call @DosInterrupt
  1070. (*%E *)
  1071. pop ds
  1072. jnc execOK
  1073. mov ax, ENOMEM
  1074. (*%F NearCall *)
  1075. call far __seterrno
  1076. (*%E *)
  1077. (*%T NearCall *)
  1078. call __seterrno
  1079. (*%E *)
  1080. mov ax, -1
  1081. jmp bgt_afterExec
  1082. execOK:
  1083. (*%F NearCall *)
  1084. call far __get_retcode
  1085. (*%E *)
  1086. (*%T NearCall *)
  1087. call __get_retcode
  1088. (*%E *)
  1089. bgt_afterExec:
  1090. mov [bp][bgt_result], ax
  1091. mov cx, [__res_mem]
  1092. (*%F NearCall *)
  1093. or cx, [__res_mem][2]
  1094. jz dontRestore
  1095. call dword [__res_mem]
  1096. (*%E *)
  1097. (*%T NearCall *)
  1098. jcxz dontRestore
  1099. call cx
  1100. (*%E *)
  1101. dontRestore:
  1102. bgt_badEnv: (* arrive here if CatEnvV failed *)
  1103. bgt_badArgs: (* arrive here if CatArgV failed *)
  1104. bgt_notFound: (* jump to here if program not found *)
  1105. bgt_end:
  1106. mov ax, [bp][bgt_result]
  1107. pop ds
  1108. pop si
  1109. pop di
  1110. call far __FloatExecRestore
  1111. mov sp, bp
  1112. pop bp
  1113. (*%F NearCall *)
  1114. ret far RetSize
  1115. (*%E *)
  1116. (*%T NearCall *)
  1117. ret RetSize
  1118. (*%E *)
  1119. (* Arrive here if cannot satisfy the request, with DOS error number in AX. *)
  1120. bgt_execFailed:
  1121. jmp bgt_afterExec
  1122. (****************************************************************************)
  1123. section
  1124. segment _TEXT(CODE,28H)
  1125. select _TEXT
  1126. $init:
  1127. (*%T NearCall*)
  1128. ret near 0
  1129. (*%E*)
  1130. (*%F NearCall*)
  1131. ret far 0
  1132. (*%E*)
  1133. segment _DATA(DATA,00028H)
  1134. extrn Str$
  1135. extrn Lib$
  1136. public SPAWN$:
  1137. (*%T NearCall*)
  1138. dw $init
  1139. (*%E*)
  1140. (*%F NearCall*)
  1141. dd $init
  1142. (*%E*)
  1143. (*%F SameDS *)
  1144. dd Str$
  1145. dd Lib$
  1146. (*%E *)
  1147. (*%T SameDS *)
  1148. dw Str$
  1149. dw Lib$
  1150. (*%E *)
  1151. dw -1
  1152. (*%E *)
  1153. (*%T _OS2 *)
  1154. (*****************************************************************************)
  1155. section
  1156. segment _TEXT(CODE,28H)
  1157. segment _DATA(DATA, 28H)
  1158. extrn __getfmode
  1159. extrn _strlen
  1160. extrn _malloc
  1161. extrn _free
  1162. extrn __seterrno
  1163. extrn _getenv
  1164. select _DATA
  1165. PATH : db 'PATH', 0
  1166. select _TEXT
  1167. public __FindProg :
  1168. (*
  1169. char *FindProg (usePath, nameP);
  1170. boolean usePath;
  1171. char *nameP;
  1172. The given file name *nameP is to be interpreted as the name of an
  1173. executable file, given the usual MSDOS rules for program names:
  1174. - if the name ends in ".*" or "." then no endings are substituted,
  1175. otherwise the endings ".COM" and ".EXE" will be the trial endings.
  1176. - if the name begins with "/" or "\" or "?:", or if the usePath
  1177. argument is false, then there are no trial prefixes, else the trial
  1178. prefixes are those in the PATH variable in the environment.
  1179. - with each prefix, beginning with a null prefix, the name is searched
  1180. for using each of its trial endings, continuing until the first
  1181. match or until all prefixes and endings have been tried.
  1182. A buffer is allocated for the trial paths. If a trial match succeeds,
  1183. the result of the function is a pointer to the buffer which holds the
  1184. complete path. The file is not open (the CHMOD function is used to
  1185. test if the file exists, not FIND). The caller is responsible to free()
  1186. the buffer when it is no longer needed.
  1187. The function result is a pointer to the buffer. If the search fails
  1188. then the buffer is de-allocated and the function result is NULL.
  1189. The function also returns the size of the path in CX, with a value of
  1190. zero if the search failed.
  1191. In the case where a path is found the caller is responsible for
  1192. deallocating the buffer, using free().
  1193. *)
  1194. fpr_usePath = sframe
  1195. fpr_nameP = 2+sframe
  1196. fpr_preP = -4
  1197. fpr_suffix = -6
  1198. fpr_len = -8
  1199. fpr_res = -10
  1200. fpr_bufP = -14
  1201. SEARCH = 80H
  1202. locals = 14
  1203. push bp
  1204. mov bp, sp
  1205. sub sp, locals
  1206. push di
  1207. push si
  1208. push ds
  1209. push es
  1210. les si, [bp][fpr_nameP]
  1211. (*%F RegParam *)
  1212. push es
  1213. push si
  1214. (*%E *)
  1215. (*%T RegParam *)
  1216. mov bx, es
  1217. mov ax, si
  1218. (*%E *)
  1219. (*%F NearCall *)
  1220. call far _strlen
  1221. (*%E *)
  1222. (*%T NearCall *)
  1223. call _strlen
  1224. (*%E *)
  1225. (*%F RegParam *)
  1226. add sp, 4
  1227. (*%E *)
  1228. xchg cx, ax (* CX is length of supplied name *)
  1229. or cx, cx
  1230. jnz fpr_hasName
  1231. mov ax, ENOENT
  1232. (*%F NearCall *)
  1233. call far __seterrno
  1234. (*%E *)
  1235. (*%T NearCall *)
  1236. call __seterrno
  1237. (*%E *)
  1238. jmp near fpr_badEnd
  1239. fpr_hasName:
  1240. mov [bp][fpr_len], cx (* keep a copy of the string length *)
  1241. mov es, [bp][fpr_nameP][2]
  1242. add si, cx (* ES:[si] point to end of string *)
  1243. dec si
  1244. std (* scan backwards *)
  1245. (* Does the name already have a specific ".*" ending ?
  1246. If the name ends in ".*" or "." then no endings are substituted.
  1247. *)
  1248. mov word [bp][fpr_suffix], FALSE (* default is a fixed ending. *)
  1249. fpr_checkEnding:
  1250. mov al, es:[si]
  1251. dec si
  1252. cmp al, '.'
  1253. je fpr_checkPrefix
  1254. cmp al, '/'
  1255. je fpr_useSuffixes
  1256. cmp al, '\'
  1257. je fpr_useSuffixes
  1258. loop fpr_checkEnding
  1259. (* The endings ".COM" and ".EXE" will be the trial endings.*)
  1260. fpr_useSuffixes:
  1261. mov word [bp][fpr_suffix], SEARCH (* enable trial endings *)
  1262. (* If the name begins with "/" or "\" or "?:" or if usePath == false
  1263. then there are no trial prefixes, else the trial prefixes are those
  1264. in the PATH= variable in the environment.
  1265. *)
  1266. fpr_checkPrefix:
  1267. cld (* forward scan *)
  1268. cmp word [bp][fpr_usePath], FALSE
  1269. je fpr_allocBuf
  1270. mov word [bp][fpr_usePath], FALSE (* default is no prefixes *)
  1271. mov cx, [bp][fpr_len]
  1272. mov si, [bp][fpr_nameP]
  1273. mov al, es:[si]
  1274. inc si
  1275. cmp al, '/'
  1276. je fpr_allocBuf
  1277. cmp al, '\'
  1278. je fpr_allocBuf
  1279. cmp al, ':'
  1280. je fpr_allocBuf
  1281. (* Prefixes are possible. Look to see if the PATH environment variable
  1282. is defined.
  1283. *)
  1284. (*%F RegParam *)
  1285. mov ax, PATH
  1286. push ds
  1287. push ax
  1288. (*%E *)
  1289. (*%T RegParam *)
  1290. mov ax, PATH
  1291. mov bx, ds
  1292. (*%E *)
  1293. (*%F NearCall *)
  1294. call far _getenv
  1295. (*%E *)
  1296. (*%T NearCall *)
  1297. call _getenv
  1298. (*%E *)
  1299. (*%F RegParam *)
  1300. add sp, 4
  1301. (*%E *)
  1302. (*%T NearPtr *)
  1303. mov bx, ax
  1304. or bx, bx
  1305. mov dx, ds
  1306. (*%E *)
  1307. (*%F NearPtr *)
  1308. mov bx, ax
  1309. or bx, dx
  1310. (*%E *)
  1311. jz fpr_allocBuf
  1312. mov [bp][fpr_preP][2], dx
  1313. mov [bp][fpr_preP], ax
  1314. mov word [bp][fpr_usePath], SEARCH (* enable prefixes. *)
  1315. (* buffer is allocated to hold the complete trial pathnames *)
  1316. fpr_allocBuf:
  1317. mov ax, 64 (* DOS paths are up to 64 chars *)
  1318. push ax
  1319. (*%F NearCall *)
  1320. call far _malloc
  1321. (*%E *)
  1322. (*%T NearCall *)
  1323. call _malloc
  1324. (*%E *)
  1325. pop bx
  1326. (*%F NearPtr *)
  1327. or dx, dx
  1328. (*%E *)
  1329. (*%T NearPtr *)
  1330. mov dx, ds
  1331. or ax, ax
  1332. (*%E *)
  1333. je near fpr_allocFailed
  1334. fpr_allocated:
  1335. mov [bp][fpr_bufP][2], dx
  1336. mov [bp][fpr_bufP], ax
  1337. (* With each prefix, beginning with a null prefix, the name is searched
  1338. for using each of its trial endings, continuing until the first
  1339. match or until all prefixes and endings have been tried.
  1340. *)
  1341. mov es, dx
  1342. xchg di, ax
  1343. sub bx, bx (* bx counts length of pathname. *)
  1344. fpr_copyName:
  1345. mov cx, [bp][fpr_len]
  1346. add bx, cx
  1347. cmp bx, 64
  1348. jnb fpr_nextPrefix
  1349. lds si, [bp][fpr_nameP]
  1350. rep ; movsb
  1351. cmp word [bp][fpr_suffix], FALSE (* are suffixes allowed ? *)
  1352. je fpr_nameFormed
  1353. add bl, 4
  1354. cmp bl, 64
  1355. jnb fpr_nextPrefix
  1356. mov ax, 432EH
  1357. stosw (* '.C' *)
  1358. mov ax, 4D4FH
  1359. stosw (* 'OM'*)
  1360. fpr_nameFormed:
  1361. lds dx, [bp][fpr_bufP]
  1362. mov byte [di], 0
  1363. push ds (* Read File's Attributes *)
  1364. push dx
  1365. (*%T RegParam *)
  1366. mov bx, ds
  1367. mov ax, dx
  1368. (*%E *)
  1369. (*%F NearCall *)
  1370. call far __getfmode
  1371. (*%E *)
  1372. (*%T NearCall *)
  1373. call __getfmode
  1374. (*%E *)
  1375. pop dx
  1376. pop ds
  1377. cmp ax, -1 (* Avoid subdir or label attributes. *)
  1378. je fpr_tryEXE
  1379. test ax, 10H
  1380. jz near fpr_found
  1381. fpr_tryEXE:
  1382. cmp word [bp][fpr_suffix], FALSE (* are suffixes allowed ? *)
  1383. je fpr_nextPrefix (* jump if not allowed. *)
  1384. mov word [di][-4], 452EH (* '.E' *)
  1385. mov word [di][-2], 4558H (* 'XE' *)
  1386. push ds (* Read File's Attributes *)
  1387. push dx
  1388. (*%T RegParam *)
  1389. mov bx, ds
  1390. mov ax, dx
  1391. (*%E *)
  1392. (*%F NearCall *)
  1393. call far __getfmode
  1394. (*%E *)
  1395. (*%T NearCall *)
  1396. call __getfmode
  1397. (*%E *)
  1398. pop dx
  1399. pop ds
  1400. cmp ax, -1 (* Avoid subdir or label attributes. *)
  1401. je fpr_nextPrefix
  1402. test ax, 10H
  1403. jz near fpr_found
  1404. (* The prefixes in the PATH variable are of the form "abc;" where abc
  1405. represents any string and ';' is a separator. The string may
  1406. also be bounded by \0, the terminator for the whole path sequence.
  1407. When there is no prefix remaining in PATH, then the search is
  1408. finished.
  1409. *)
  1410. fpr_nextPrefix:
  1411. cmp word [bp][fpr_usePath], FALSE (* are prefixes allowed ? *)
  1412. je fpr_notFound
  1413. lds si, [bp][fpr_preP] (* copy the next path prefix *)
  1414. sub bx, bx
  1415. mov cx, 60
  1416. les di, [bp][fpr_bufP] (* into the working buffer. *)
  1417. fpr_scanPrefix:
  1418. lodsb
  1419. cmp al, ';'
  1420. je fpr_preSeparator
  1421. cmp al, 0
  1422. je fpr_preTerminator
  1423. stosb
  1424. inc bx
  1425. loop fpr_scanPrefix
  1426. jmp fpr_notFound (* give up if PATH is badly formed. *)
  1427. fpr_preTerminator:
  1428. dec si (* the terminator cannot be passed. *)
  1429. fpr_preSeparator:
  1430. mov [bp][fpr_preP], si (* remember where the PATH continues. *)
  1431. or bx, bx (* was that the end of the PATH ? *)
  1432. jz fpr_notFound
  1433. mov al, es:[di][-1] (* may need to insert '\' *)
  1434. cmp al, '\'
  1435. je fpr_joinable
  1436. cmp al, ':'
  1437. je fpr_joinable
  1438. cmp al, '/'
  1439. je fpr_joinable
  1440. mov al, '\'
  1441. stosb
  1442. inc bx
  1443. fpr_joinable:
  1444. jmp fpr_copyName (* join name to trial path *)
  1445. (* If not found, then de-allocate the name buffer. *)
  1446. fpr_notFound:
  1447. mov ax, _DATA
  1448. mov ds, ax
  1449. (*%F RegParam *)
  1450. push [bp][fpr_bufP][2]
  1451. push [bp][fpr_bufP]
  1452. (*%E *)
  1453. (*%T RegParam *)
  1454. mov bx, [bp][fpr_bufP][2]
  1455. mov ax, [bp][fpr_bufP]
  1456. (*%E *)
  1457. (*%F NearCall *)
  1458. call far _free
  1459. (*%E *)
  1460. (*%T NearCall *)
  1461. call _free
  1462. (*%E *)
  1463. (*%F RegParam *)
  1464. add sp, 4
  1465. (*%E *)
  1466. mov ax, ENOENT
  1467. (*%F NearCall *)
  1468. call far __seterrno
  1469. (*%E *)
  1470. (*%T NearCall *)
  1471. call __seterrno
  1472. (*%E *)
  1473. fpr_allocFailed:
  1474. fpr_badEnd:
  1475. sub ax, ax
  1476. cwd
  1477. mov cx, ax
  1478. jmp fpr_end
  1479. fpr_found:
  1480. mov ax, dx
  1481. mov dx, ds
  1482. mov cx, _DATA (* DX:AX points to the name *)
  1483. mov ds, cx
  1484. mov cx, di
  1485. inc cx (* include the terminating zero *)
  1486. sub cx, ax (* CX = length of name *)
  1487. fpr_end:
  1488. pop es
  1489. pop ds
  1490. pop si
  1491. pop di
  1492. mov sp, bp
  1493. pop bp
  1494. ret 0
  1495. (*****************************************************************************)
  1496. section
  1497. segment _TEXT(CODE,28H)
  1498. segment _DATA(DATA, 28H)
  1499. extrn _getenv
  1500. extrn _strlen
  1501. extrn _strcpy
  1502. extrn _malloc
  1503. extrn _free
  1504. extrn __seterrno
  1505. select _DATA
  1506. select _TEXT
  1507. extrn _malloc
  1508. extrn _strlen
  1509. public __CatArgV :
  1510. (*
  1511. char *_CatArgV (argV)
  1512. char *argV [];
  1513. The return value is a pointer to the argComposite, in DX:AX, with the
  1514. total length of the argComposite in CX. If an error occurs, then
  1515. DX:AX == NULL and CX == 0.
  1516. *)
  1517. cav_argV = sframe
  1518. cav_path = 4+sframe
  1519. cav_bufP = -4
  1520. locals = 4
  1521. push bp
  1522. mov bp, sp
  1523. sub sp, locals
  1524. push di
  1525. push si
  1526. push ds
  1527. push es
  1528. sub di, di (* DI = total length of arguments *)
  1529. lds si, [bp][cav_argV]
  1530. mov ax, ds
  1531. (*%F NearPtr *)
  1532. or ax, si
  1533. (*%E *)
  1534. (*%T NearPtr *)
  1535. or si, si
  1536. (*%E *)
  1537. jz cav_argVnull (* NULL argV is allowed, arg total == 0 *)
  1538. cav_measureNext: (* note: argV[0] deliberately skipped *)
  1539. (*%F NearPtr *)
  1540. add si, 4
  1541. les bx, [si]
  1542. mov ax, es
  1543. or ax, bx
  1544. jz cav_allMeasured
  1545. (*%E *)
  1546. (*%T NearPtr *)
  1547. add si, 2
  1548. mov bx, [si]
  1549. or bx, bx
  1550. jz cav_allMeasured
  1551. (*%E *)
  1552. (*%F RegParam *)
  1553. push es
  1554. push bx
  1555. (*%E *)
  1556. (*%T RegParam *)
  1557. mov ax, bx
  1558. mov bx, es
  1559. (*%E *)
  1560. (*%F NearCall *)
  1561. call far _strlen
  1562. (*%E *)
  1563. (*%T NearCall *)
  1564. call _strlen
  1565. (*%E *)
  1566. (*%F RegParam *)
  1567. add sp, 4
  1568. (*%E *)
  1569. add di, ax
  1570. inc di (* plus a separating space *)
  1571. jmp cav_measureNext
  1572. cav_argVnull:
  1573. inc di (* allow for trailing 0 *)
  1574. cav_allMeasured:
  1575. mov ax, _DATA (* is command line NearPtr enough ? *)
  1576. mov ds, ax
  1577. cmp di, 127
  1578. ja cav_tooLarge
  1579. (*%F RegParam *)
  1580. push [bp][cav_path][2]
  1581. push [bp][cav_path]
  1582. (*%E *)
  1583. (*%T RegParam *)
  1584. mov bx, [bp][cav_path][2]
  1585. mov ax, [bp][cav_path]
  1586. (*%E *)
  1587. (*%F NearCall *)
  1588. call far _strlen
  1589. (*%E *)
  1590. (*%T NearCall *)
  1591. call _strlen
  1592. (*%E *)
  1593. (*%F RegParam *)
  1594. add sp, 4
  1595. (*%E *)
  1596. inc ax
  1597. mov si, ax
  1598. mov di, 100H (* OS2 needs max seg size *)
  1599. add di, ax
  1600. (*%T RegParam *)
  1601. mov ax, di
  1602. (*%E *)
  1603. push di
  1604. (*%F NearCall *)
  1605. call far _malloc
  1606. (*%E *)
  1607. (*%T NearCall *)
  1608. call _malloc
  1609. (*%E *)
  1610. pop bx
  1611. (*%F RegParam *)
  1612. (*%F NearPtr *)
  1613. or dx, dx
  1614. je cav_allocFailed
  1615. mov [bp][cav_bufP][2], dx
  1616. mov [bp][cav_bufP], ax
  1617. push [bp][cav_path][2]
  1618. push [bp][cav_path]
  1619. push dx
  1620. push ax
  1621. (*%E *)
  1622. (*%T NearPtr *)
  1623. mov dx, ds
  1624. or ax, ax
  1625. je cav_allocFailed
  1626. mov [bp][cav_bufP][2], dx
  1627. mov [bp][cav_bufP], ax
  1628. push [bp][cav_path]
  1629. push ax
  1630. (*%E *)
  1631. (*%E *)
  1632. (*%T RegParam *)
  1633. (*%F NearPtr *)
  1634. or dx, dx
  1635. je cav_allocFailed
  1636. mov [bp][cav_bufP][2], dx
  1637. mov [bp][cav_bufP], ax
  1638. mov bx, dx
  1639. mov dx, [bp][cav_path][2]
  1640. mov cx, [bp][cav_path]
  1641. (*%E *)
  1642. (*%T NearPtr *)
  1643. mov dx, ds
  1644. or ax, ax
  1645. je cav_allocFailed
  1646. mov [bp][cav_bufP][2], dx
  1647. mov [bp][cav_bufP], ax
  1648. mov bx, [bp][cav_path]
  1649. (*%E *)
  1650. (*%E *)
  1651. (*%F NearCall *)
  1652. call far _strcpy
  1653. (*%E *)
  1654. (*%T NearCall *)
  1655. call _strcpy
  1656. (*%E *)
  1657. (*%F RegParam *)
  1658. (*%F NearPtr *)
  1659. add sp, 8
  1660. (*%E *)
  1661. (*%T NearPtr *)
  1662. add sp, 4
  1663. (*%E *)
  1664. (*%E *)
  1665. cav_copyArgs:
  1666. les di, [bp][cav_bufP]
  1667. add di, si
  1668. mov bx, [bp][cav_argV]
  1669. cav_nextArg:
  1670. mov ds, [bp][cav_argV][2]
  1671. mov ax, ds
  1672. or ax, bx (* is argV == NULL ? *)
  1673. jz cav_terminate
  1674. (*%F NearPtr *)
  1675. add bx, 4 (* next argument *)
  1676. lds si, [bx]
  1677. mov ax, ds
  1678. or ax, si
  1679. jz cav_terminate
  1680. (*%E *)
  1681. (*%T NearPtr *)
  1682. add bx, 2 (* next argument *)
  1683. mov si, [bx]
  1684. or si, si
  1685. jz cav_terminate
  1686. (*%E *)
  1687. mov al, ' '
  1688. stosb
  1689. cav_copyLoop:
  1690. lodsb (* copy argument *)
  1691. or al, al
  1692. jz cav_nextArg
  1693. stosb (* to the new command line *)
  1694. jmp cav_copyLoop
  1695. cav_tooLarge:
  1696. mov ax, E2BIG
  1697. (*%F NearCall *)
  1698. call far __seterrno
  1699. (*%E *)
  1700. (*%T NearCall *)
  1701. call __seterrno
  1702. (*%E *)
  1703. cav_allocFailed:
  1704. sub ax, ax (* return a NULL pointer *)
  1705. cwd
  1706. mov cx, ax (* and a zero length *)
  1707. jmp cav_end
  1708. cav_terminate:
  1709. mov ax, _DATA
  1710. mov ds, ax
  1711. sub al, al
  1712. stosb
  1713. mov cx, di
  1714. (* The argComposite is now complete. *)
  1715. mov ax, [bp][cav_bufP]
  1716. sub cx, ax
  1717. mov dx, es
  1718. cav_end:
  1719. pop es
  1720. pop ds
  1721. pop si
  1722. pop di
  1723. mov sp, bp
  1724. pop bp
  1725. ret 0
  1726. (*****************************************************************************)
  1727. section
  1728. segment _TEXT(CODE,28H)
  1729. segment _DATA(DATA, 28H)
  1730. extrn _getenv
  1731. extrn _strlen
  1732. extrn _malloc
  1733. extrn _free
  1734. extrn __seterrno
  1735. select _DATA
  1736. extrn __env_var
  1737. select _TEXT
  1738. extrn _malloc
  1739. extrn _strlen
  1740. public __CatEnvV :
  1741. (*
  1742. char *_CatEnvV (envV)
  1743. char *envV [];
  1744. The register CX returns the length of the environment string, including
  1745. the terminating zero. CX == 0 in cases of error.
  1746. *)
  1747. cev_envV = sframe
  1748. cev_bufP = -4
  1749. locals = 4
  1750. push bp
  1751. mov bp, sp
  1752. sub sp, locals
  1753. push di
  1754. push si
  1755. push ds
  1756. les si, [bp][cev_envV]
  1757. mov ax, es
  1758. (*%F NearPtr *)
  1759. or ax, si (* is a NULL parameter supplied ? *)
  1760. (*%E *)
  1761. (*%T NearPtr *)
  1762. or si, si
  1763. (*%E *)
  1764. jnz cev_envVset
  1765. mov ax, seg __env_var
  1766. mov es, ax (* if so, return parent's environ. *)
  1767. mov si, __env_var
  1768. mov [bp][cev_envV], si
  1769. mov [bp][cev_envV][2], es
  1770. cev_envVset:
  1771. push es
  1772. pop ds
  1773. sub di, di (* DI = total length of strings *)
  1774. cev_measureNext:
  1775. (*%F NearPtr *)
  1776. les bx, [si]
  1777. add si, 4
  1778. mov ax, es
  1779. or ax, bx
  1780. jz cev_allMeasured
  1781. (*%E *)
  1782. (*%T NearPtr *)
  1783. mov bx, [si]
  1784. add si, 2
  1785. or bx, bx
  1786. jz cev_allMeasured
  1787. (*%E *)
  1788. (*%F RegParam *)
  1789. push es
  1790. push bx
  1791. (*%E *)
  1792. (*%T RegParam *)
  1793. mov ax, bx
  1794. mov bx, es
  1795. (*%E *)
  1796. (*%F NearCall *)
  1797. call far _strlen
  1798. (*%E *)
  1799. (*%T NearCall *)
  1800. call _strlen
  1801. (*%E *)
  1802. (*%F RegParam *)
  1803. add sp, 4
  1804. (*%E *)
  1805. or ax, ax
  1806. jz cev_allMeasured
  1807. add di, ax
  1808. inc di (* plus a terminating \0 *)
  1809. jmp cev_measureNext
  1810. cev_allMeasured:
  1811. inc di (* plus an overall terminator \0 *)
  1812. mov ax, _DATA
  1813. mov ds, ax
  1814. cmp di, 32767-15
  1815. ja cev_tooLarge
  1816. lea ax, [di][0FH] (* allow for paragraph alignment *)
  1817. push ax
  1818. (*%F NearCall *)
  1819. call far _malloc
  1820. (*%E *)
  1821. (*%T NearCall *)
  1822. call _malloc
  1823. (*%E *)
  1824. pop bx
  1825. (*%F NearPtr *)
  1826. or dx, dx
  1827. (*%E *)
  1828. (*%T NearPtr *)
  1829. mov dx, ds
  1830. or ax, ax
  1831. (*%E *)
  1832. jz cev_allocFailed
  1833. mov [bp][cev_bufP][2], dx
  1834. mov [bp][cev_bufP], ax
  1835. (* Now the environment is allocated. Copy the strings into it. *)
  1836. mov es, dx
  1837. mov di, ax
  1838. mov bx, [bp][cev_envV]
  1839. cev_nextArg:
  1840. (*%F NearPtr *)
  1841. mov ds, [bp][cev_envV][2]
  1842. lds si, [bx]
  1843. add bx, 4 (* next string *)
  1844. mov ax, ds
  1845. or ax, si
  1846. jz cev_terminate
  1847. cmp byte [si], 0
  1848. je cev_terminate
  1849. (*%E *)
  1850. (*%T NearPtr *)
  1851. mov si, [bx]
  1852. add bx, 2 (* next string *)
  1853. or si, si
  1854. jz cev_terminate
  1855. cmp byte [si], 0
  1856. je cev_terminate
  1857. (*%E *)
  1858. cev_copyLoop:
  1859. lodsb (* copy string *)
  1860. or al, al
  1861. stosb (* to the new environment *)
  1862. jnz cev_copyLoop
  1863. jmp cev_nextArg
  1864. cev_tooLarge:
  1865. mov ax, E2BIG
  1866. jmp cev_errorRet
  1867. cev_allocFailed:
  1868. mov ax, ENOMEM
  1869. cev_errorRet:
  1870. (*%F NearCall *)
  1871. call far __seterrno
  1872. (*%E *)
  1873. (*%T NearCall *)
  1874. call __seterrno
  1875. (*%E *)
  1876. sub ax, ax (* return a NULL pointer *)
  1877. cwd
  1878. mov cx, -1 (* with zero size. *)
  1879. jmp cev_end
  1880. cev_terminate:
  1881. mov ax, _DATA
  1882. mov ds, ax
  1883. mov al, 0 (* overall terminator zero *)
  1884. stosb
  1885. (* The environment is now complete. *)
  1886. mov ax, [bp][cev_bufP] (* DX:AX = &allocation block *)
  1887. mov dx, [bp][cev_bufP][2] (* ES:0 = &environment. *)
  1888. mov cx, di (* CX = size of environment. *)
  1889. sub cx, ax
  1890. cev_end:
  1891. pop ds
  1892. pop si
  1893. pop di
  1894. mov sp, bp
  1895. pop bp
  1896. ret 0
  1897. (****************************************************************************)
  1898. section
  1899. segment _TEXT(CODE,28H)
  1900. segment _DATA(DATA, 28H)
  1901. extrn _exit
  1902. extrn _free
  1903. extrn __FindProg
  1904. extrn __CatArgV
  1905. extrn __CatEnvV
  1906. extrn __seterrno
  1907. extrn __FloatExecSave
  1908. extrn __FloatExecRestore
  1909. extrn DOSEXECPGM
  1910. select _DATA
  1911. extrn __env
  1912. select _TEXT
  1913. EXEC_SYNC = 0
  1914. EXEC_ASYNC = 1
  1915. EXEC_ASYNCRESULT = 2
  1916. EXEC_TRACE = 3
  1917. EXEC_BACKGROUND = 4
  1918. EXEC_LOAD = 5
  1919. SEARCH = 80H
  1920. P_WAIT = 0
  1921. P_NOWAIT = 1
  1922. P_OVERLAY = 2
  1923. public __beget :
  1924. (*
  1925. int _beget (pathP, argV, envV, flag)
  1926. char *pathP;
  1927. char *argV [];
  1928. char *envV [];
  1929. int flag
  1930. A child process, with program identified by *pathP, is found, validated,
  1931. and executed. The current process continues to exist but is asleep
  1932. until the child process is finished.
  1933. A return value of -1 indicates that the child process could not be
  1934. If usePath is true then the PATH environment variable will be used to
  1935. help find the program name, otherwise *pathP is assumed to include
  1936. directory names and the PATH is not used. However, in either case
  1937. the suffixes ".COM" and ".EXE" will automatically be tried unless
  1938. the supplied name already ends with an extention.
  1939. *)
  1940. codeTerminate = 0
  1941. codeResult = 2
  1942. (*%F RegParam *)
  1943. RetSize = 0
  1944. (*%E *)
  1945. (*%T RegParam *)
  1946. (*%T NearPtr *)
  1947. RetSize = 0
  1948. (*%E *)
  1949. (*%F NearPtr *)
  1950. RetSize = 6
  1951. (*%E *)
  1952. (*%E *)
  1953. (*%F RegParam *)
  1954. path = frame
  1955. (*%F NearPtr *)
  1956. argv = 4+frame
  1957. env = 8+frame
  1958. flag = 12+frame
  1959. (*%E *)
  1960. (*%T NearPtr *)
  1961. argv = 2+frame
  1962. env = 4+frame
  1963. flag = 6+frame
  1964. (*%E *)
  1965. argbuf = -4
  1966. envbuf = -8
  1967. pathbuf = -12
  1968. resbuf = -16
  1969. locals = 16
  1970. (*%E *)
  1971. (*%T RegParam *)
  1972. (*%F NearPtr *)
  1973. flag = frame
  1974. env = 2+frame
  1975. argbuf = -4
  1976. envbuf = -8
  1977. pathbuf = -12
  1978. resbuf = -16
  1979. path = -20
  1980. argv = -24
  1981. locals = 24
  1982. (*%E *)
  1983. (*%T NearPtr *)
  1984. argbuf = -4
  1985. envbuf = -8
  1986. pathbuf = -12
  1987. resbuf = -16
  1988. path = -18
  1989. argv = -20
  1990. env = -22
  1991. flag = -24
  1992. locals = 24
  1993. (*%E *)
  1994. (*%E *)
  1995. push bp
  1996. mov bp, sp
  1997. sub sp, locals
  1998. call far __FloatExecSave
  1999. (*%T RegParam *)
  2000. (*%F NearPtr *)
  2001. mov [bp][path], ax
  2002. mov [bp][path][2], bx
  2003. mov [bp][argv], cx
  2004. mov [bp][argv][2], dx
  2005. (*%E *)
  2006. (*%T NearPtr *)
  2007. mov [bp][path], ax
  2008. mov [bp][argv], bx
  2009. mov [bp][env], cx
  2010. mov [bp][flag], dx
  2011. (*%E *)
  2012. (*%E *)
  2013. push di
  2014. push si
  2015. (*%F SameDS *)
  2016. push ds
  2017. mov ax, seg __env
  2018. mov ds, ax
  2019. (*%E *)
  2020. (*%F NearPtr *)
  2021. push [bp][path][2]
  2022. (*%E *)
  2023. (*%T NearPtr *)
  2024. push ds
  2025. (*%E *)
  2026. push [bp][path]
  2027. mov ax, [bp][flag]
  2028. and ax, SEARCH
  2029. push ax
  2030. call __FindProg
  2031. add sp, 6
  2032. jcxz near notFound
  2033. mov [bp][pathbuf][2], dx
  2034. mov [bp][pathbuf], ax
  2035. push dx
  2036. push ax
  2037. (*%F NearPtr *)
  2038. push [bp][argv][2]
  2039. (*%E *)
  2040. (*%T NearPtr *)
  2041. push ds
  2042. (*%E *)
  2043. push [bp][argv]
  2044. call __CatArgV
  2045. add sp, 8
  2046. jcxz near badargv
  2047. mov [bp][argbuf][2], dx
  2048. mov [bp][argbuf], ax
  2049. (*%F NearPtr *)
  2050. push [bp][env][2]
  2051. (*%E *)
  2052. (*%T NearPtr *)
  2053. push ds
  2054. (*%E *)
  2055. push [bp][env]
  2056. call __CatEnvV
  2057. add sp, 4
  2058. cmp cx, -1
  2059. je near badenv
  2060. mov [bp][envbuf][2], dx
  2061. mov [bp][envbuf], ax
  2062. mov ax, [bp][flag]
  2063. and ax, ~SEARCH
  2064. mov [bp][flag], ax
  2065. call __selectmode
  2066. cmp ax, -1
  2067. je badMode
  2068. sub bx, bx
  2069. push bx
  2070. push bx
  2071. push bx
  2072. push ax
  2073. push [bp][argbuf][2]
  2074. push [bp][argbuf]
  2075. mov ax, [bp][envbuf][2]
  2076. or ax, ax
  2077. jnz envNew
  2078. mov ax, [__env]
  2079. sub bx, bx
  2080. jmp envSet
  2081. envNew:
  2082. mov bx, [bp][envbuf]
  2083. envSet:
  2084. push ax
  2085. push bx
  2086. push ss
  2087. lea ax, [bp][resbuf]
  2088. push ax
  2089. push [bp][pathbuf][2]
  2090. push [bp][pathbuf]
  2091. call far DOSEXECPGM
  2092. or ax, ax
  2093. jnz begetError
  2094. mov ax, [bp][flag]
  2095. cmp ax, P_OVERLAY
  2096. je terminate
  2097. cmp ax, P_WAIT
  2098. je getRetcode
  2099. mov si, [bp][resbuf][codeTerminate] (* child's PID *)
  2100. jmp begetDone
  2101. getRetcode: (* child's return code *)
  2102. mov si, [bp][resbuf][codeResult]
  2103. begetDone:
  2104. call __freeenv
  2105. call __freeargv
  2106. call __freepath
  2107. mov ax, si
  2108. begetExit:
  2109. (*%F SameDS *)
  2110. pop ds
  2111. (*%E *)
  2112. pop si
  2113. pop di
  2114. call far __FloatExecRestore
  2115. mov sp, bp
  2116. pop bp
  2117. (*%F NearCall *)
  2118. ret far RetSize
  2119. (*%E *)
  2120. (*%T NearCall *)
  2121. ret RetSize
  2122. (*%E *)
  2123. terminate:
  2124. sub ax, ax
  2125. (*%F RegParam *)
  2126. push ax
  2127. (*%E *)
  2128. (*%F NearCall *)
  2129. call far _exit
  2130. (*%E *)
  2131. (*%T NearCall *)
  2132. call _exit
  2133. (*%E *)
  2134. badMode:
  2135. call __freepath
  2136. call __freeargv
  2137. call __freeenv
  2138. mov ax, EINVAL
  2139. jmp begetError
  2140. notFound:
  2141. mov ax, ENOPATH
  2142. jmp begetError
  2143. badargv:
  2144. call __freepath
  2145. mov ax, E2BIG
  2146. jmp begetError
  2147. badenv:
  2148. call __freepath
  2149. call __freeargv
  2150. mov ax, E2BIG
  2151. jmp begetError
  2152. begetError:
  2153. (*%F NearCall *)
  2154. call far __seterrno
  2155. (*%E *)
  2156. (*%T NearCall *)
  2157. call __seterrno
  2158. (*%E *)
  2159. mov ax, -1
  2160. jmp begetExit
  2161. __freepath :
  2162. (*%F RegParam *)
  2163. push [bp][pathbuf][2]
  2164. push [bp][pathbuf]
  2165. (*%E *)
  2166. (*%T RegParam *)
  2167. mov bx, [bp][pathbuf][2]
  2168. mov ax, [bp][pathbuf]
  2169. (*%E *)
  2170. (*%F NearCall *)
  2171. call far _free
  2172. (*%E *)
  2173. (*%T NearCall *)
  2174. call _free
  2175. (*%E *)
  2176. (*%F RegParam *)
  2177. add sp, 4
  2178. (*%E *)
  2179. ret 0
  2180. __freeargv :
  2181. (*%F RegParam *)
  2182. push [bp][argbuf][2]
  2183. push [bp][argbuf]
  2184. (*%E *)
  2185. (*%T RegParam *)
  2186. mov bx, [bp][argbuf][2]
  2187. mov ax, [bp][argbuf]
  2188. (*%E *)
  2189. (*%F NearCall *)
  2190. call far _free
  2191. (*%E *)
  2192. (*%T NearCall *)
  2193. call _free
  2194. (*%E *)
  2195. (*%F RegParam *)
  2196. add sp, 4
  2197. (*%E *)
  2198. ret 0
  2199. __freeenv :
  2200. mov cx, [bp][envbuf][2]
  2201. jcxz dontFree
  2202. (*%F RegParam *)
  2203. push cx
  2204. push [bp][envbuf]
  2205. (*%E *)
  2206. (*%T RegParam *)
  2207. mov bx, cx
  2208. mov ax, [bp][envbuf]
  2209. (*%E *)
  2210. (*%F NearCall *)
  2211. call far _free
  2212. (*%E *)
  2213. (*%T NearCall *)
  2214. call _free
  2215. (*%E *)
  2216. (*%F RegParam *)
  2217. add sp, 4
  2218. (*%E *)
  2219. dontFree:
  2220. ret 0
  2221. __selectmode :
  2222. cmp ax, P_WAIT
  2223. jne s1
  2224. mov ax, EXEC_SYNC
  2225. jmp done
  2226. s1:
  2227. cmp ax, P_NOWAIT
  2228. jne s2
  2229. mov ax, EXEC_ASYNC
  2230. jmp done
  2231. s2:
  2232. cmp ax, P_OVERLAY
  2233. jne serr
  2234. mov ax, EXEC_ASYNC
  2235. jmp done
  2236. serr:
  2237. mov ax, -1
  2238. done:
  2239. ret 0
  2240. section
  2241. segment _TEXT(CODE,28H)
  2242. select _TEXT
  2243. $init:
  2244. (*%T NearCall*)
  2245. ret near 0
  2246. (*%E*)
  2247. (*%F NearCall*)
  2248. ret far 0
  2249. (*%E*)
  2250. segment _DATA(DATA,00028H)
  2251. public SPAWN$:
  2252. (*%T NearCall*)
  2253. dw $init
  2254. (*%E*)
  2255. (*%F NearCall*)
  2256. dd $init
  2257. (*%E*)
  2258. dw -1
  2259. (*%E *)
  2260. end
  2261.