| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661 |
- (* Release 3.10 *)
- (*-------------------------------------------------------------------------*
- * *
- * SPAWN.A - child process spawning *
- * *
- * COPYRIGHT (C) 1989..1992 Clarion Software Corporation. *
- * All Rights Reserved *
- * *
- *--------------------------------------------------------------------------*)
- include "corelib.inc"
- module SPAWN
- (*%F _OS2 *)
- (****************************************************************************)
- section
- segment _TEXT(CODE,28H)
- segment _DATA(DATA, 28H)
- extrn Str$RCharPos
- extrn Str$Length
- select _TEXT
- public __CatProg :
- ptr = sframe
- temp = -4
- locals = 4
- push bp
- mov bp, sp
- sub sp, locals
- les bx, [bp][ptr]
- (*%F NearPtr *)
- mov dx, '\'
- mov cx, es:[bx][2]
- mov bx, es:[bx]
- mov ax, 128
- (*%E *)
- (*%T NearPtr *)
- mov cx, '\'
- mov bx, es:[bx]
- mov ax, 128
- (*%E *)
- (*%F RegParam *)
- (*%F NearPtr *)
- push ax
- push cx
- push bx
- push dx
- (*%E *)
- (*%T NearPtr *)
- push ax
- push bx
- push cx
- (*%E *)
- (*%E *)
- (*%F NearCall *)
- call far Str$RCharPos
- (*%E *)
- (*%T NearCall *)
- call Str$RCharPos
- (*%E *)
- cmp ax, -1
- pushf
- add ax, [bp][ptr]
- mov dx, [bp][ptr][2]
- popf
- jnz getLength
- les bx, [bp][ptr]
- mov ax, es:[bx]
- (*%F NearPtr *)
- mov dx, es:[bx][2]
- (*%E *)
- getLength:
- mov [bp][temp], ax
- (*%F NearPtr *)
- mov [bp][temp][2], dx
- mov bx, dx
- (*%E *)
- (*%T NearPtr *)
- mov [bp][temp][2], ds
- (*%E *)
- (*%F NearPtr *)
- mov cx, bx
- (*%E *)
- mov bx, ax
- mov ax, 128
- (*%F RegParam *)
- (*%T NearPtr *)
- push ax
- push bx
- (*%E *)
- (*%F NearPtr *)
- push ax
- push cx
- push bx
- (*%E *)
- (*%E *)
- (*%F NearCall *)
- call far Str$Length
- (*%E *)
- (*%T NearCall *)
- call Str$Length
- (*%E *)
- mov cx, ax
- mov ax, [bp][temp]
- mov dx, [bp][temp][2]
- mov sp, bp
- pop bp
- ret 0
- (*****************************************************************************)
- section
- segment _TEXT(CODE,28H)
- segment _DATA(DATA, 28H)
- SEARCH = 80H
- extrn Str$Length
- extrn Lib$EnvironmentFind
- select _DATA
- extrn __seterrno
- PATH : db 'PATH', 0
- select _TEXT
- public __FindProg :
- (*
- char *FindProg (usePath, nameP);
- boolean usePath;
- char *nameP;
- The given file name *nameP is to be interpreted as the name of an
- executable file, given the usual MSDOS rules for program names:
- - if the name ends in ".*" or "." then no endings are substituted,
- otherwise the endings ".COM" and ".EXE" will be the trial endings.
- - if the name begins with "/" or "\" or "?:", or if the usePath
- argument is false, then there are no trial prefixes, else the trial
- prefixes are those in the PATH variable in the environment.
- - with each prefix, beginning with a null prefix, the name is searched
- for using each of its trial endings, continuing until the first
- match or until all prefixes and endings have been tried.
- A buffer is allocated for the trial paths. If a trial match succeeds,
- the result of the function is a pointer to the buffer which holds the
- complete path. The file is not open (the CHMOD function is used to
- test if the file exists, not FIND). The caller is responsible to free()
- the buffer when it is no longer needed.
- The function result is a pointer to the buffer. If the search fails
- then the buffer is de-allocated and the function result is NULL.
- The function also returns the size of the path in CX, with a value of
- zero if the search failed.
- In the case where a path is found the caller is responsible for
- deallocating the buffer, using free().
- *)
- fpr_bufP = sframe
- fpr_usePath = 4+sframe
- fpr_nameP = 6+sframe
- fpr_preP = -4
- fpr_suffix = -6
- fpr_len = -8
- fpr_res = -10
- PathStr = -142
- locals = 142
- push bp
- mov bp, sp
- sub sp, locals
- push di
- push si
- push ds
- push es
- les si, [bp][fpr_nameP]
- (*%F RegParam *)
- mov ax, 128
- push ax
- (*%F NearPtr *)
- push es
- (*%E *)
- push si
- (*%E *)
- (*%T RegParam *)
- mov ax, 128
- mov cx, es
- mov bx, si
- (*%E *)
- (*%F NearCall *)
- call far Str$Length
- (*%E *)
- (*%T NearCall *)
- call Str$Length
- (*%E *)
- xchg cx, ax (* CX is length of supplied name *)
- or cx, cx
- jnz fpr_hasName
- mov ax, ENOENT
- (*%F NearCall *)
- call far __seterrno
- (*%E *)
- (*%T NearCall *)
- call __seterrno
- (*%E *)
- jmp near fpr_badEnd
- fpr_hasName:
- mov [bp][fpr_len], cx (* keep a copy of the string length *)
- mov es, [bp][fpr_nameP][2]
- add si, cx (* ES:[si] point to end of string *)
- dec si
- std (* scan backwards *)
- (* Does the name already have a specific ".*" ending ?
- If the name ends in ".*" or "." then no endings are substituted.
- *)
- mov word [bp][fpr_suffix], FALSE (* default is a fixed ending. *)
- fpr_checkEnding:
- mov al, es:[si]
- dec si
- cmp al, '.'
- je fpr_checkPrefix
- cmp al, '/'
- je fpr_useSuffixes
- cmp al, '\'
- je fpr_useSuffixes
- loop fpr_checkEnding
- (* The endings ".COM" and ".EXE" will be the trial endings.*)
- fpr_useSuffixes:
- mov word [bp][fpr_suffix], TRUE (* enable trial endings *)
- (* If the name begins with "/" or "\" or "?:" or if usePath == false
- then there are no trial prefixes, else the trial prefixes are those
- in the PATH= variable in the environment.
- *)
- fpr_checkPrefix:
- cld (* forward scan *)
- cmp word [bp][fpr_usePath], FALSE
- je fpr_allocBuf
- mov word [bp][fpr_usePath], FALSE (* default is no prefixes *)
- mov cx, [bp][fpr_len]
- mov si, [bp][fpr_nameP]
- mov al, es:[si]
- inc si
- cmp al, '/'
- je fpr_allocBuf
- cmp al, '\'
- je fpr_allocBuf
- cmp al, ':'
- je fpr_allocBuf
- (* Prefixes are possible. Look to see if the PATH environment variable
- is defined.
- *)
- (*%F RegParam *)
- (*%F NearPtr *)
- mov ax, 4
- push ax
- mov ax, PATH
- push ds
- push ax
- mov ax, 128
- push ax
- lea ax, [bp][PathStr]
- push ss
- push ax
- (*%E *)
- (*%T NearPtr *)
- mov ax, 4
- push ax
- mov ax, PATH
- push ax
- mov ax, 128
- push ax
- lea ax, [bp][PathStr]
- push ax
- (*%E *)
- (*%E *)
- (*%T RegParam *)
- (*%F NearPtr *)
- lea ax, [bp][PathStr]
- push ss
- push ax
- mov ax, 4
- mov bx, PATH
- mov cx, ds
- mov dx, 128
- (*%E *)
- (*%T NearPtr *)
- mov ax, 4
- mov bx, PATH
- mov cx, 128
- lea dx, [bp][PathStr]
- (*%E *)
- (*%E *)
- (*%F NearCall *)
- call far Lib$EnvironmentFind
- (*%E *)
- (*%T NearCall *)
- call Lib$EnvironmentFind
- (*%E *)
- lea ax, [bp][PathStr]
- cmp byte [bp][PathStr], 0
- jz fpr_allocBuf
- mov [bp][fpr_preP][2], ss
- mov [bp][fpr_preP], ax
- mov word [bp][fpr_usePath], SEARCH (* enable prefixes. *)
- (* buffer is allocated to hold the complete trial pathnames *)
- fpr_allocBuf:
- (* With each prefix, beginning with a null prefix, the name is searched
- for using each of its trial endings, continuing until the first
- match or until all prefixes and endings have been tried.
- *)
- mov dx, [bp][fpr_bufP][2]
- mov ax, [bp][fpr_bufP]
- mov es, dx
- xchg di, ax
- sub bx, bx (* bx counts length of pathname. *)
- fpr_copyName:
- mov cx, [bp][fpr_len]
- add bx, cx
- cmp bx, 64
- jnb fpr_nextPrefix
- lds si, [bp][fpr_nameP]
- rep ; movsb
- cmp word [bp][fpr_suffix], FALSE (* are suffixes allowed ? *)
- je fpr_nameFormed
- add bl, 4
- cmp bl, 64
- jnb fpr_nextPrefix
- mov ax, 432EH
- stosw (* '.C' *)
- mov ax, 4D4FH
- stosw (* 'OM'*)
- fpr_nameFormed:
- lds dx, [bp][fpr_bufP]
- mov byte [di], 0
- mov ax, 4300H (* Read File's Attributes *)
- extrn @DosInterrupt
- (*%F NearCall *)
- call far @DosInterrupt
- (*%E *)
- (*%T NearCall *)
- call @DosInterrupt
- (*%E *)
- jc fpr_tryEXE
- test cl, 18H (* Avoid subdir or label attributes. *)
- jz near fpr_found
- fpr_tryEXE:
- cmp word [bp][fpr_suffix], FALSE (* are suffixes allowed ? *)
- je fpr_nextPrefix (* jump if not allowed. *)
- mov word [di][-4], 452EH (* '.E' *)
- mov word [di][-2], 4558H (* 'XE' *)
- mov ax, 4300H (* Read File's Attributes *)
- extrn @DosInterrupt
- (*%F NearCall *)
- call far @DosInterrupt
- (*%E *)
- (*%T NearCall *)
- call @DosInterrupt
- (*%E *)
- jc fpr_nextPrefix
- test cl, 18H (* Avoid subdir or label attributes. *)
- jz fpr_found
- (* The prefixes in the PATH variable are of the form "abc;" where abc
- represents any string and ';' is a separator. The string may
- also be bounded by \0, the terminator for the whole path sequence.
- When there is no prefix remaining in PATH, then the search is
- finished.
- *)
- fpr_nextPrefix:
- cmp word [bp][fpr_usePath], FALSE (* are prefixes allowed ? *)
- je fpr_notFound
- lds si, [bp][fpr_preP] (* copy the next path prefix *)
- sub bx, bx
- mov cx, 60
- les di, [bp][fpr_bufP] (* into the working buffer. *)
- fpr_scanPrefix:
- lodsb
- cmp al, ';'
- je fpr_preSeparator
- cmp al, 0
- je fpr_preTerminator
- stosb
- inc bx
- loop fpr_scanPrefix
- jmp fpr_notFound (* give up if PATH is badly formed. *)
- fpr_preTerminator:
- dec si (* the terminator cannot be passed. *)
- fpr_preSeparator:
- mov [bp][fpr_preP], si (* remember where the PATH continues. *)
- or bx, bx (* was that the end of the PATH ? *)
- jz fpr_notFound
- mov al, es:[di][-1] (* may need to insert '\' *)
- cmp al, '\'
- je fpr_joinable
- cmp al, ':'
- je fpr_joinable
- cmp al, '/'
- je fpr_joinable
- mov al, '\'
- stosb
- inc bx
- fpr_joinable:
- jmp fpr_copyName (* join name to trial path *)
- (* If not found, then de-allocate the name buffer. *)
- fpr_notFound:
- mov ax, ENOENT
- (*%F NearCall *)
- call far __seterrno
- (*%E *)
- (*%T NearCall *)
- call __seterrno
- (*%E *)
- fpr_allocFailed:
- fpr_badEnd:
- sub ax, ax
- cwd
- mov cx, ax
- jmp fpr_end
- fpr_found:
- mov ax, dx
- mov dx, ds
- mov cx, _DATA (* DX:AX points to the name *)
- mov ds, cx
- mov cx, di
- inc cx (* include the terminating zero *)
- sub cx, ax (* CX = length of name *)
- fpr_end:
- pop es
- pop ds
- pop si
- pop di
- mov sp, bp
- pop bp
- ret 0
- (*****************************************************************************)
- section
- segment _TEXT(CODE,28H)
- segment _DATA(DATA, 28H)
- extrn Str$Length
- extrn __seterrno
- select _TEXT
- extrn Str$Length
- public __CatArgV :
- (*
- char *_CatArgV (argV)
- char *argV [];
- Take the vector of arguments and concatenate them into an MSDOS-style
- command line. Use a space to separate each argument, with a maximu of
- 126 characters, plus a preceding length byte and a following CR ('0x0D').
- Also, check the assumption that *argV[1] and *argV[2] may be MSDOS 1.xx
- style (CPM-era) file names. If so, construct FCBs from them.
- A NULL entry in the argV vector is taken as a terminator. The entry
- argV[0] by Unix convention is a command name which should not appear in
- the MSDOS command line, so it is entirely ignored here.
- Allocate a structure to hold the two FCBs and the command line. If the
- command line does not overflow, then the return value is the pointer to
- the structure:
- argComposite
- FCB1 char [16];
- FCB2 char [16];
- length char;
- text char [127]; /* includes trailing 0x0D */
- The size of the arguments is calculated. If it will total more than
- 126 bytes, including spaces, then the function quits without allocating
- an argComposite. If the total is OK, then the size of argComposite is
- trimmed to hold just the necessary number of characters.
- The return value is a pointer to the argComposite, in DX:AX, with the
- total length of the argComposite in CX. If an error occurs, then
- DX:AX == NULL and CX == 0.
- *)
- cav_bufP = sframe
- cav_argV = 4+sframe
- locals = 4
- push bp
- mov bp, sp
- sub sp, locals
- push di
- push si
- push ds
- push es
- sub di, di (* DI = total length of arguments *)
- lds si, [bp][cav_argV]
- mov ax, ds
- or ax, si
- jz cav_argVnull (* NULL argV is allowed, arg total == 0 *)
- cav_measureNext: (* note: argV[0] deliberately skipped *)
- (*%F NearPtr *)
- add si, 4
- les bx, [si]
- mov ax, es
- or ax, bx
- (*%E *)
- (*%T NearPtr *)
- add si, 2
- mov bx, [si]
- or bx, bx
- (*%E *)
- jz cav_allMeasured
- (*%F RegParam *)
- mov ax, 128
- push ax
- (*%F NearPtr *)
- push es
- (*%E *)
- push bx
- (*%E *)
- (*%T RegParam *)
- mov ax, 128
- mov cx, es
- (*%E *)
- (*%F NearCall *)
- call far Str$Length
- (*%E *)
- (*%T NearCall *)
- call Str$Length
- (*%E *)
- add di, ax
- inc di (* plus a separating space or final CR *)
- jmp cav_measureNext
- cav_argVnull:
- inc di (* allow for trailing CR *)
- cav_allMeasured:
- mov ax, _DATA (* is command line NearPtr enough ? *)
- mov ds, ax
- cmp di, 127
- ja cav_tooLarge
- mov dx, [bp][cav_bufP][2]
- mov ax, [bp][cav_bufP]
- (* Now the composite is allocated. First fill out the FCB headers, using
- *argV[1] & [2]. *)
- mov es, dx
- xchg di, ax
- mov word es:[di], 20FFH (* default FCBs *)
- mov word es:[di][10H], 20FFH (* are marked as empty. *)
- lds si, [bp][cav_argV]
- mov ax, ds
- or ax, si
- jz cav_copyArgs (* no FCBs if argV == NULL *)
- (*%F NearPtr *)
- lds si, [si][4] (* argV[1] *)
- mov ax, ds
- or ax, si
- (*%E *)
- (*%T NearPtr *)
- mov si, [si][2] (* argV[1] *)
- or si, si
- (*%E *)
- jz cav_copyArgs
- mov ax, 2901H (* parse filename, allow leading spaces *)
- extrn @DosInterrupt
- (*%F NearCall *)
- call far @DosInterrupt
- (*%E *)
- (*%T NearCall *)
- call @DosInterrupt
- (*%E *)
- add di, 10H (* point to the second FCB *)
- lds si, [bp][cav_argV]
- (*%F NearPtr *)
- lds si, [si][8] (* argV[1] *)
- mov ax, ds
- or ax, si
- (*%E *)
- (*%T NearPtr *)
- mov si, [si][4] (* argV[1] *)
- or si, si
- (*%E *)
- jz cav_copyArgs
- mov ax, 2901H (* parse filename, allow leading spaces *)
- extrn @DosInterrupt
- (*%F NearCall *)
- call far @DosInterrupt
- (*%E *)
- (*%T NearCall *)
- call @DosInterrupt
- (*%E *)
- cav_copyArgs:
- les di, [bp][cav_bufP]
- add di, 21H (* begin after the length byte *)
- lea cx, [di][-1] (* remember where the length byte is. *)
- mov bx, [bp][cav_argV]
- cav_nextArg:
- (*%F NearPtr *)
- mov ds, [bp][cav_argV][2]
- mov ax, ds
- or ax, bx (* is argV == NULL ? *)
- jz cav_terminate
- add bx, 4 (* next argument *)
- lds si, [bx]
- mov ax, ds
- or ax, si
- jz cav_terminate
- (*%E *)
- (*%T NearPtr *)
- or bx, bx (* is argV == NULL ? *)
- jz cav_terminate
- add bx, 2 (* next argument *)
- mov si, [bx]
- or si, si
- jz cav_terminate
- (*%E *)
- mov al, ' ' (* separate the arguments *)
- stosb
- cav_copyLoop:
- lodsb (* copy argument *)
- or al, al
- jz cav_nextArg
- stosb (* to the new command line *)
- jmp cav_copyLoop
- cav_tooLarge:
- mov ax, E2BIG
- (*%F NearCall *)
- call far __seterrno
- (*%E *)
- (*%T NearCall *)
- call __seterrno
- (*%E *)
- cav_allocFailed:
- sub ax, ax (* return a NULL pointer *)
- cwd
- mov cx, ax (* and a zero length *)
- jmp cav_end
- cav_terminate:
- mov ax, _DATA
- mov ds, ax
- mov al, 0DH (* arriage return *)
- stosb
- xchg di, cx (* DI = &lengthByte, CX = &last byte *)
- mov ax, [bp][cav_bufP]
- sub cx, ax (* CX = composite length *)
- mov bx, cx
- sub bl, 22H
- mov es:[di], bl (* prefix the command line with length *)
- (* The argComposite is now complete. *)
- mov dx, es
- cav_end:
- pop es
- pop ds
- pop si
- pop di
- mov sp, bp
- pop bp
- ret 0
- (*****************************************************************************)
- section
- segment _TEXT(CODE,28H)
- segment _DATA(DATA, 28H)
- extrn Str$Length
- select _DATA
- extrn __seterrno
- extrn __env_var
- select _TEXT
- extrn Str$Length
- public __CatEnvV :
- (*
- char *_CatEnvV (envV)
- char *envV [];
- Take the environment vector and concatenate the environment strings into
- an MSDOS-style contiguous environment. Each string remains terminated by
- a zero, with a null string as an overall terminator and a maximum length
- of 32k bytes.
- If a NULL envV value is supplied, then replace it with the global _environ
- variable.
- The size of the environment is totalled, and if it does not exceed 32k bytes
- then a space is allocated, including 15 byte extra for paragraph alignment.
- The environment is adjusted to begin on a paragraph boundary since MSDOS
- uses segment values alone to locate environment strings.
- A NULL entry in the envV vector or a pointer to an empty string are taken
- as terminators.
- The return value in DX:AX is the pointer to the allocated memory (NULL if
- none allocated). The register ES contains the paragraph number at which
- the environment string actually begins (zero if none allocated). Note
- that while MSDOS needs only the ES value, the DX:AX pointer will in general
- be required in order to free() the allocation.
- The register CX returns the length of the environment string, including
- the terminating zero. CX == 0 in cases of error.
- *)
- cev_bufP = sframe
- cev_envV = 4+sframe
- locals = 4
- push bp
- mov bp, sp
- sub sp, locals
- push di
- push si
- push ds
- les si, [bp][cev_envV]
- (*%F NearPtr *)
- mov ax, es
- or ax, si
- (*%E *)
- (*%T NearPtr *)
- or si, si (* is a NULL parameter supplied ? *)
- (*%E *)
- jnz cev_envVset
- sub ax, ax
- mov es, ax
- mov dx, ax
- mov cx, 1
- jmp near cev_end
- cev_envVset:
- push es
- pop ds
- sub di, di (* DI = total length of strings *)
- cev_measureNext:
- (*%F NearPtr *)
- les bx, [si]
- add si, 4
- mov ax, es
- or ax, bx
- jz cev_allMeasured
- (*%F RegParam *)
- mov ax, 128
- push ax
- (*%F NearPtr *)
- push es
- (*%E *)
- push bx
- (*%E *)
- (*%T RegParam *)
- mov ax, 128
- mov cx, es
- (*%E *)
- (*%F NearCall *)
- call far Str$Length
- (*%E *)
- (*%T NearCall *)
- call Str$Length
- (*%E *)
- or ax, ax
- jz cev_allMeasured
- add di, ax
- inc di (* plus a terminating \0 *)
- jmp cev_measureNext
- (*%E *)
- (*%T NearPtr *)
- mov bx, [si]
- add si, 2
- or bx, bx
- jz cev_allMeasured
- (*%F RegParam *)
- mov ax, 128
- push ax
- (*%F NearPtr *)
- push es
- (*%E *)
- push bx
- (*%E *)
- (*%T RegParam *)
- mov ax, 128
- mov cx, es
- (*%E *)
- (*%F NearCall *)
- call far Str$Length
- (*%E *)
- (*%T NearCall *)
- call Str$Length
- (*%E *)
- or ax, ax
- jz cev_allMeasured
- add di, ax
- inc di (* plus a terminating \0 *)
- jmp cev_measureNext
- (*%E *)
- cev_allMeasured:
- inc di (* plus an overall terminator \0 *)
- mov ax, _DATA
- mov ds, ax
- cmp di, ARG_BUF_SIZE-0FH
- ja cev_tooLarge
- mov dx, [bp][cev_bufP][2]
- mov ax, [bp][cev_bufP]
- (* Align the environment on a paragraph boundary. *)
- add ax, 15
- mov cl, 4
- shr ax, cl
- add dx, ax
- sub ax, ax (* DX:AX is now paragraph aligned *)
- (* Now the environment is allocated. Copy the strings into it. *)
- mov es, dx
- mov di, ax
- mov bx, [bp][cev_envV]
- cev_nextArg:
- (*%F NearPtr *)
- mov ds, [bp][cev_envV][2]
- lds si, [bx]
- add bx, 4 (* next string *)
- mov ax, ds
- or ax, si
- jz cev_terminate
- cmp byte [si], 0
- je cev_terminate
- (*%E *)
- (*%T NearPtr *)
- mov si, [bx]
- add bx, 2 (* next string *)
- or si, si
- jz cev_terminate
- cmp byte [si], 0
- je cev_terminate
- (*%E *)
- cev_copyLoop:
- lodsb (* copy string *)
- or al, al
- stosb (* to the new environment *)
- jnz cev_copyLoop
- jmp cev_nextArg
- cev_tooLarge:
- mov ax, E2BIG
- (*%F NearCall *)
- call far __seterrno
- (*%E *)
- (*%T NearCall *)
- call __seterrno
- (*%E *)
- cev_allocFailed:
- sub ax, ax (* return a NULL pointer *)
- cwd
- mov cx, ax (* with zero size. *)
- jmp cev_end
- cev_terminate:
- mov ax, _DATA
- mov ds, ax
- mov al, 0 (* overall terminator zero *)
- stosb
- (* The environment is now complete. *)
- mov cx, di (* CX = size of environment. *)
- mov ax, [bp][cev_bufP] (* DX:AX = &allocation block *)
- mov dx, [bp][cev_bufP][2] (* ES:0 = &environment. *)
- cev_end:
- pop ds
- pop si
- pop di
- mov sp, bp
- pop bp
- ret 0
- (*****************************************************************************)
- section
- segment _TEXT(CODE,28H)
- segment _DATA(DATA, 28H)
- extrn __shr_mem
- extrn __res_mem
- extrn __get_retcode
- extrn __FindProg
- extrn __CatArgV
- extrn __CatEnvV
- extrn __FloatExecSave
- extrn __FloatExecRestore
- select _DATA
- extrn __seterrno
- extrn __fmemsetup
- select _TEXT
- public __beget :
- (*
- int _beget (pathP, argV, envV, flag)
- char *pathP;
- char *argV [];
- char *envV [];
- int flag
- A child process, with program identified by *pathP, is found, validated,
- and executed. The current process continues to exist but is asleep
- until the child process is finished.
- A return value of -1 indicates that the child process could not be
- created. Otherwise, the return value will be the exit code of the
- child process, which by convention is zero if the child executed
- without fault. The exact meaning and severity of non-zero exit
- codes are not standardised.
- If usePath is true then the PATH environment variable will be used to
- help find the program name, otherwise *pathP is assumed to include
- directory names and the PATH is not used. However, in either case
- the suffixes ".COM" and ".EXE" will automatically be tried unless
- the supplied name already ends with an extention.
- Method
- The basis for the begetting of a child process is the MSDOS Exec command,
- function 4Bh request kind 0. However, there are several preliminary actions
- required. Firstly the exact and complete program name must be found, which
- involves tracing the PATH= environment variable. This is done by the
- _FindProg function.
- Next the arguments must be scanned and concatenated into a single command
- string of up to 126 bytes, plus a length byte and a trailing carriage return.
- Arguments [1] and [2] may be file names, and so the MSDOS Parse Filename
- function (29h) is used to build matching FCB's if possible. This is done
- with the _CatArgV function.
- Note that argument [0] is by convention the same as pathP. It is not used
- and not checked. The end of the argV vector must be set by placing a NULL
- pointer in the final element of the vector.
- The envV vector points to a collection of environment strings. These must
- also be concatenated into a contiguous region of up to 32k bytes, terminated
- with a double zero, which is the form expected by Exec. This is done by the
- _CatEnvV function. The envV vector is terminated either by a NULL pointer
- or by a pointer to a null string. If envV == NULL then the current program's
- environment is used.
- When all these things have been done the child program may be executed using
- function 4Bh, with the environment, command line, and dummy FCBs supplied as
- parameters to function 4Bh. After the child has terminated, function 4Dh is
- used to pick up the exit code.
- *)
- (*%F RegParam *)
- RetSize = 0
- (*%E *)
- (*%T RegParam *)
- (*%T NearPtr *)
- RetSize = 0
- (*%E *)
- (*%F NearPtr *)
- RetSize = 6
- (*%E *)
- (*%E *)
- (*%F RegParam *)
- bgt_pathP = frame
- (*%F NearPtr *)
- bgt_argV = 4+frame
- bgt_envV = 8+frame
- bgt_flag = 12+frame
- (*%E *)
- (*%T NearPtr *)
- bgt_argV = 2+frame
- bgt_envV = 4+frame
- bgt_flag = 6+frame
- (*%E *)
- bgt_fullP = - 4
- bgt_environ = - 8
- bgt_params = -22
- bgt_result = -24
- bgt_ProgBuf = -94
- bgt_ArgBuf = -254
- bgt_EnvBuf = bgt_ArgBuf-ARG_BUF_SIZE
- locals = -bgt_EnvBuf
- (*%E *)
- (*%T RegParam *)
- (*%F NearPtr *)
- bgt_envV = 2+frame
- bgt_flag = frame
- bgt_fullP = - 4
- bgt_environ = - 8
- bgt_params = -22
- bgt_result = -24
- bgt_pathP = -28
- bgt_argV = -32
- bgt_ProgBuf = -102
- bgt_ArgBuf = -262
- bgt_EnvBuf = bgt_ArgBuf-ARG_BUF_SIZE
- locals = -bgt_EnvBuf
- (*%E *)
- (*%T NearPtr *)
- bgt_fullP = - 4
- bgt_environ = - 8
- bgt_params = -22
- bgt_result = -24
- bgt_pathP = -26
- bgt_argV = -28
- bgt_envV = -30
- bgt_flag = -32
- bgt_ProgBuf = -102
- bgt_ArgBuf = -262
- bgt_EnvBuf = bgt_ArgBuf-ARG_BUF_SIZE
- locals = -bgt_EnvBuf
- (*%E *)
- (*%E *)
- push bp
- (*%T StackChecks *)
- mov bp, locals+40
- (*%F NearCall *)
- extrn F$StkChk
- call far F$StkChk
- (*%E *)
- (*%T NearCall *)
- extrn N$StkChk
- call N$StkChk
- (*%E *)
- (*%E *)
- mov bp, sp
- sub sp, locals
- call far __FloatExecSave
- (*%T RegParam *)
- (*%F NearPtr *)
- mov [bp][bgt_pathP], ax
- mov [bp][bgt_pathP][2], bx
- mov [bp][bgt_argV], cx
- mov [bp][bgt_argV][2], dx
- (*%E *)
- (*%T NearPtr *)
- mov [bp][bgt_pathP], ax
- mov [bp][bgt_argV], bx
- mov [bp][bgt_envV], cx
- mov [bp][bgt_flag], dx
- (*%E *)
- (*%E *)
- push di
- push si
- push ds
- (*%F SameDS *)
- mov ax, seg __fmemsetup
- mov ds, ax
- (*%E *)
- mov word [bp][bgt_result], -1 (* default if Exec can't be done *)
- (* The exact and complete program name must be found. *)
- (*%F NearPtr *)
- push [bp][bgt_pathP][2]
- (*%E *)
- (*%T NearPtr *)
- push ds
- (*%E *)
- push [bp][bgt_pathP]
- push [bp][bgt_flag] (* the usePath flag. *)
- push ss
- lea ax, [bp][bgt_ProgBuf]
- push ax
- call __FindProg
- add sp, 10
- or cx, cx
- jnz bgt_progFound
- jmp near bgt_notFound
- bgt_progFound:
- mov [bp][bgt_fullP], ax (*the full path of the program file *)
- mov [bp][bgt_fullP][2], dx
- (* The arguments must be scanned and concatenated into a single command
- string of up to 126 bytes, plus a length byte and a trailing CR.
- Args [1] and [2] are used to build matching FCB's if possible.
- *)
- (*%F NearPtr *)
- push [bp][bgt_argV][2]
- (*%E *)
- (*%T NearPtr *)
- push ds
- (*%E *)
- push [bp][bgt_argV]
- push ss
- lea ax, [bp][bgt_ArgBuf]
- push ax
- call __CatArgV (* returns FCB1, FCB2, command line, at DX:AX *)
- add sp, 8
- jcxz bgt_badArgs
- mov [bp][bgt_params][8], dx (* pointer to FCB1 *)
- mov [bp][bgt_params][6], ax
- add ax, 10H
- mov [bp][bgt_params][12], dx (* pointer to FCB2 *)
- mov [bp][bgt_params][10], ax
- add ax, 10H
- mov [bp][bgt_params][4], dx (* pointer to command line *)
- mov [bp][bgt_params][2], ax
- (* The environment strings must also be concatenated into a contiguous region
- of up to 32k bytes, terminated with a double zero.
- *)
- (*%F NearPtr *)
- push [bp][bgt_envV][2]
- (*%E *)
- (*%T NearPtr *)
- push ds
- (*%E *)
- push [bp][bgt_envV]
- push ss
- lea ax, [bp][bgt_EnvBuf]
- push ax
- call __CatEnvV (* returns environment at DX:AX, ES:0 *)
- add sp, 8
- jcxz bgt_badEnv
- mov [bp][bgt_environ], ax
- mov [bp][bgt_environ][2], dx
- mov [bp][bgt_params], es (* paragraph aligned within DX:AX *)
- (* Open a memory space. *)
- mov cx, [__shr_mem]
- sub ax, ax
- (*%F NearCall *)
- or cx, [__shr_mem][2]
- jz dontShrink
- call dword [__shr_mem]
- (*%E *)
- (*%T NearCall *)
- jcxz dontShrink
- call cx
- (*%E *)
- dontShrink:
- (* The child program may be executed using function 4Bh. *)
- push ds
- push ss
- pop es
- lds dx, [bp][bgt_fullP]
- lea bx, [bp][bgt_params]
- mov ax, 4B00H (* Execute (DS:DX using ES:BX) *)
- extrn @DosInterrupt
- (*%F NearCall *)
- call far @DosInterrupt
- (*%E *)
- (*%T NearCall *)
- call @DosInterrupt
- (*%E *)
- pop ds
- jnc execOK
- mov ax, ENOMEM
- (*%F NearCall *)
- call far __seterrno
- (*%E *)
- (*%T NearCall *)
- call __seterrno
- (*%E *)
- mov ax, -1
- jmp bgt_afterExec
- execOK:
- (*%F NearCall *)
- call far __get_retcode
- (*%E *)
- (*%T NearCall *)
- call __get_retcode
- (*%E *)
- bgt_afterExec:
- mov [bp][bgt_result], ax
- mov cx, [__res_mem]
- (*%F NearCall *)
- or cx, [__res_mem][2]
- jz dontRestore
- call dword [__res_mem]
- (*%E *)
- (*%T NearCall *)
- jcxz dontRestore
- call cx
- (*%E *)
- dontRestore:
- bgt_badEnv: (* arrive here if CatEnvV failed *)
- bgt_badArgs: (* arrive here if CatArgV failed *)
- bgt_notFound: (* jump to here if program not found *)
- bgt_end:
- mov ax, [bp][bgt_result]
- pop ds
- pop si
- pop di
- call far __FloatExecRestore
- mov sp, bp
- pop bp
- (*%F NearCall *)
- ret far RetSize
- (*%E *)
- (*%T NearCall *)
- ret RetSize
- (*%E *)
- (* Arrive here if cannot satisfy the request, with DOS error number in AX. *)
- bgt_execFailed:
- jmp bgt_afterExec
- (****************************************************************************)
- section
- segment _TEXT(CODE,28H)
- select _TEXT
- $init:
- (*%T NearCall*)
- ret near 0
- (*%E*)
- (*%F NearCall*)
- ret far 0
- (*%E*)
- segment _DATA(DATA,00028H)
- extrn Str$
- extrn Lib$
- public SPAWN$:
- (*%T NearCall*)
- dw $init
- (*%E*)
- (*%F NearCall*)
- dd $init
- (*%E*)
- (*%F SameDS *)
- dd Str$
- dd Lib$
- (*%E *)
- (*%T SameDS *)
- dw Str$
- dw Lib$
- (*%E *)
- dw -1
- (*%E *)
- (*%T _OS2 *)
- (*****************************************************************************)
- section
- segment _TEXT(CODE,28H)
- segment _DATA(DATA, 28H)
- extrn __getfmode
- extrn _strlen
- extrn _malloc
- extrn _free
- extrn __seterrno
- extrn _getenv
- select _DATA
- PATH : db 'PATH', 0
- select _TEXT
- public __FindProg :
- (*
- char *FindProg (usePath, nameP);
- boolean usePath;
- char *nameP;
- The given file name *nameP is to be interpreted as the name of an
- executable file, given the usual MSDOS rules for program names:
- - if the name ends in ".*" or "." then no endings are substituted,
- otherwise the endings ".COM" and ".EXE" will be the trial endings.
- - if the name begins with "/" or "\" or "?:", or if the usePath
- argument is false, then there are no trial prefixes, else the trial
- prefixes are those in the PATH variable in the environment.
- - with each prefix, beginning with a null prefix, the name is searched
- for using each of its trial endings, continuing until the first
- match or until all prefixes and endings have been tried.
- A buffer is allocated for the trial paths. If a trial match succeeds,
- the result of the function is a pointer to the buffer which holds the
- complete path. The file is not open (the CHMOD function is used to
- test if the file exists, not FIND). The caller is responsible to free()
- the buffer when it is no longer needed.
- The function result is a pointer to the buffer. If the search fails
- then the buffer is de-allocated and the function result is NULL.
- The function also returns the size of the path in CX, with a value of
- zero if the search failed.
- In the case where a path is found the caller is responsible for
- deallocating the buffer, using free().
- *)
- fpr_usePath = sframe
- fpr_nameP = 2+sframe
- fpr_preP = -4
- fpr_suffix = -6
- fpr_len = -8
- fpr_res = -10
- fpr_bufP = -14
- SEARCH = 80H
- locals = 14
- push bp
- mov bp, sp
- sub sp, locals
- push di
- push si
- push ds
- push es
- les si, [bp][fpr_nameP]
- (*%F RegParam *)
- push es
- push si
- (*%E *)
- (*%T RegParam *)
- mov bx, es
- mov ax, si
- (*%E *)
- (*%F NearCall *)
- call far _strlen
- (*%E *)
- (*%T NearCall *)
- call _strlen
- (*%E *)
- (*%F RegParam *)
- add sp, 4
- (*%E *)
- xchg cx, ax (* CX is length of supplied name *)
- or cx, cx
- jnz fpr_hasName
- mov ax, ENOENT
- (*%F NearCall *)
- call far __seterrno
- (*%E *)
- (*%T NearCall *)
- call __seterrno
- (*%E *)
- jmp near fpr_badEnd
- fpr_hasName:
- mov [bp][fpr_len], cx (* keep a copy of the string length *)
- mov es, [bp][fpr_nameP][2]
- add si, cx (* ES:[si] point to end of string *)
- dec si
- std (* scan backwards *)
- (* Does the name already have a specific ".*" ending ?
- If the name ends in ".*" or "." then no endings are substituted.
- *)
- mov word [bp][fpr_suffix], FALSE (* default is a fixed ending. *)
- fpr_checkEnding:
- mov al, es:[si]
- dec si
- cmp al, '.'
- je fpr_checkPrefix
- cmp al, '/'
- je fpr_useSuffixes
- cmp al, '\'
- je fpr_useSuffixes
- loop fpr_checkEnding
- (* The endings ".COM" and ".EXE" will be the trial endings.*)
- fpr_useSuffixes:
- mov word [bp][fpr_suffix], SEARCH (* enable trial endings *)
- (* If the name begins with "/" or "\" or "?:" or if usePath == false
- then there are no trial prefixes, else the trial prefixes are those
- in the PATH= variable in the environment.
- *)
- fpr_checkPrefix:
- cld (* forward scan *)
- cmp word [bp][fpr_usePath], FALSE
- je fpr_allocBuf
- mov word [bp][fpr_usePath], FALSE (* default is no prefixes *)
- mov cx, [bp][fpr_len]
- mov si, [bp][fpr_nameP]
- mov al, es:[si]
- inc si
- cmp al, '/'
- je fpr_allocBuf
- cmp al, '\'
- je fpr_allocBuf
- cmp al, ':'
- je fpr_allocBuf
- (* Prefixes are possible. Look to see if the PATH environment variable
- is defined.
- *)
- (*%F RegParam *)
- mov ax, PATH
- push ds
- push ax
- (*%E *)
- (*%T RegParam *)
- mov ax, PATH
- mov bx, ds
- (*%E *)
- (*%F NearCall *)
- call far _getenv
- (*%E *)
- (*%T NearCall *)
- call _getenv
- (*%E *)
- (*%F RegParam *)
- add sp, 4
- (*%E *)
- (*%T NearPtr *)
- mov bx, ax
- or bx, bx
- mov dx, ds
- (*%E *)
- (*%F NearPtr *)
- mov bx, ax
- or bx, dx
- (*%E *)
- jz fpr_allocBuf
- mov [bp][fpr_preP][2], dx
- mov [bp][fpr_preP], ax
- mov word [bp][fpr_usePath], SEARCH (* enable prefixes. *)
- (* buffer is allocated to hold the complete trial pathnames *)
- fpr_allocBuf:
- mov ax, 64 (* DOS paths are up to 64 chars *)
- push ax
- (*%F NearCall *)
- call far _malloc
- (*%E *)
- (*%T NearCall *)
- call _malloc
- (*%E *)
- pop bx
- (*%F NearPtr *)
- or dx, dx
- (*%E *)
- (*%T NearPtr *)
- mov dx, ds
- or ax, ax
- (*%E *)
- je near fpr_allocFailed
- fpr_allocated:
- mov [bp][fpr_bufP][2], dx
- mov [bp][fpr_bufP], ax
- (* With each prefix, beginning with a null prefix, the name is searched
- for using each of its trial endings, continuing until the first
- match or until all prefixes and endings have been tried.
- *)
- mov es, dx
- xchg di, ax
- sub bx, bx (* bx counts length of pathname. *)
- fpr_copyName:
- mov cx, [bp][fpr_len]
- add bx, cx
- cmp bx, 64
- jnb fpr_nextPrefix
- lds si, [bp][fpr_nameP]
- rep ; movsb
- cmp word [bp][fpr_suffix], FALSE (* are suffixes allowed ? *)
- je fpr_nameFormed
- add bl, 4
- cmp bl, 64
- jnb fpr_nextPrefix
- mov ax, 432EH
- stosw (* '.C' *)
- mov ax, 4D4FH
- stosw (* 'OM'*)
- fpr_nameFormed:
- lds dx, [bp][fpr_bufP]
- mov byte [di], 0
- push ds (* Read File's Attributes *)
- push dx
- (*%T RegParam *)
- mov bx, ds
- mov ax, dx
- (*%E *)
- (*%F NearCall *)
- call far __getfmode
- (*%E *)
- (*%T NearCall *)
- call __getfmode
- (*%E *)
- pop dx
- pop ds
- cmp ax, -1 (* Avoid subdir or label attributes. *)
- je fpr_tryEXE
- test ax, 10H
- jz near fpr_found
- fpr_tryEXE:
- cmp word [bp][fpr_suffix], FALSE (* are suffixes allowed ? *)
- je fpr_nextPrefix (* jump if not allowed. *)
- mov word [di][-4], 452EH (* '.E' *)
- mov word [di][-2], 4558H (* 'XE' *)
- push ds (* Read File's Attributes *)
- push dx
- (*%T RegParam *)
- mov bx, ds
- mov ax, dx
- (*%E *)
- (*%F NearCall *)
- call far __getfmode
- (*%E *)
- (*%T NearCall *)
- call __getfmode
- (*%E *)
- pop dx
- pop ds
- cmp ax, -1 (* Avoid subdir or label attributes. *)
- je fpr_nextPrefix
- test ax, 10H
- jz near fpr_found
- (* The prefixes in the PATH variable are of the form "abc;" where abc
- represents any string and ';' is a separator. The string may
- also be bounded by \0, the terminator for the whole path sequence.
- When there is no prefix remaining in PATH, then the search is
- finished.
- *)
- fpr_nextPrefix:
- cmp word [bp][fpr_usePath], FALSE (* are prefixes allowed ? *)
- je fpr_notFound
- lds si, [bp][fpr_preP] (* copy the next path prefix *)
- sub bx, bx
- mov cx, 60
- les di, [bp][fpr_bufP] (* into the working buffer. *)
- fpr_scanPrefix:
- lodsb
- cmp al, ';'
- je fpr_preSeparator
- cmp al, 0
- je fpr_preTerminator
- stosb
- inc bx
- loop fpr_scanPrefix
- jmp fpr_notFound (* give up if PATH is badly formed. *)
- fpr_preTerminator:
- dec si (* the terminator cannot be passed. *)
- fpr_preSeparator:
- mov [bp][fpr_preP], si (* remember where the PATH continues. *)
- or bx, bx (* was that the end of the PATH ? *)
- jz fpr_notFound
- mov al, es:[di][-1] (* may need to insert '\' *)
- cmp al, '\'
- je fpr_joinable
- cmp al, ':'
- je fpr_joinable
- cmp al, '/'
- je fpr_joinable
- mov al, '\'
- stosb
- inc bx
- fpr_joinable:
- jmp fpr_copyName (* join name to trial path *)
- (* If not found, then de-allocate the name buffer. *)
- fpr_notFound:
- mov ax, _DATA
- mov ds, ax
- (*%F RegParam *)
- push [bp][fpr_bufP][2]
- push [bp][fpr_bufP]
- (*%E *)
- (*%T RegParam *)
- mov bx, [bp][fpr_bufP][2]
- mov ax, [bp][fpr_bufP]
- (*%E *)
- (*%F NearCall *)
- call far _free
- (*%E *)
- (*%T NearCall *)
- call _free
- (*%E *)
- (*%F RegParam *)
- add sp, 4
- (*%E *)
- mov ax, ENOENT
- (*%F NearCall *)
- call far __seterrno
- (*%E *)
- (*%T NearCall *)
- call __seterrno
- (*%E *)
- fpr_allocFailed:
- fpr_badEnd:
- sub ax, ax
- cwd
- mov cx, ax
- jmp fpr_end
- fpr_found:
- mov ax, dx
- mov dx, ds
- mov cx, _DATA (* DX:AX points to the name *)
- mov ds, cx
- mov cx, di
- inc cx (* include the terminating zero *)
- sub cx, ax (* CX = length of name *)
- fpr_end:
- pop es
- pop ds
- pop si
- pop di
- mov sp, bp
- pop bp
- ret 0
- (*****************************************************************************)
- section
- segment _TEXT(CODE,28H)
- segment _DATA(DATA, 28H)
- extrn _getenv
- extrn _strlen
- extrn _strcpy
- extrn _malloc
- extrn _free
- extrn __seterrno
- select _DATA
- select _TEXT
- extrn _malloc
- extrn _strlen
- public __CatArgV :
- (*
- char *_CatArgV (argV)
- char *argV [];
- The return value is a pointer to the argComposite, in DX:AX, with the
- total length of the argComposite in CX. If an error occurs, then
- DX:AX == NULL and CX == 0.
- *)
- cav_argV = sframe
- cav_path = 4+sframe
- cav_bufP = -4
- locals = 4
- push bp
- mov bp, sp
- sub sp, locals
- push di
- push si
- push ds
- push es
- sub di, di (* DI = total length of arguments *)
- lds si, [bp][cav_argV]
- mov ax, ds
- (*%F NearPtr *)
- or ax, si
- (*%E *)
- (*%T NearPtr *)
- or si, si
- (*%E *)
- jz cav_argVnull (* NULL argV is allowed, arg total == 0 *)
- cav_measureNext: (* note: argV[0] deliberately skipped *)
- (*%F NearPtr *)
- add si, 4
- les bx, [si]
- mov ax, es
- or ax, bx
- jz cav_allMeasured
- (*%E *)
- (*%T NearPtr *)
- add si, 2
- mov bx, [si]
- or bx, bx
- jz cav_allMeasured
- (*%E *)
- (*%F RegParam *)
- push es
- push bx
- (*%E *)
- (*%T RegParam *)
- mov ax, bx
- mov bx, es
- (*%E *)
- (*%F NearCall *)
- call far _strlen
- (*%E *)
- (*%T NearCall *)
- call _strlen
- (*%E *)
- (*%F RegParam *)
- add sp, 4
- (*%E *)
- add di, ax
- inc di (* plus a separating space *)
- jmp cav_measureNext
- cav_argVnull:
- inc di (* allow for trailing 0 *)
- cav_allMeasured:
- mov ax, _DATA (* is command line NearPtr enough ? *)
- mov ds, ax
- cmp di, 127
- ja cav_tooLarge
- (*%F RegParam *)
- push [bp][cav_path][2]
- push [bp][cav_path]
- (*%E *)
- (*%T RegParam *)
- mov bx, [bp][cav_path][2]
- mov ax, [bp][cav_path]
- (*%E *)
- (*%F NearCall *)
- call far _strlen
- (*%E *)
- (*%T NearCall *)
- call _strlen
- (*%E *)
- (*%F RegParam *)
- add sp, 4
- (*%E *)
- inc ax
- mov si, ax
- mov di, 100H (* OS2 needs max seg size *)
- add di, ax
- (*%T RegParam *)
- mov ax, di
- (*%E *)
- push di
- (*%F NearCall *)
- call far _malloc
- (*%E *)
- (*%T NearCall *)
- call _malloc
- (*%E *)
- pop bx
- (*%F RegParam *)
- (*%F NearPtr *)
- or dx, dx
- je cav_allocFailed
- mov [bp][cav_bufP][2], dx
- mov [bp][cav_bufP], ax
- push [bp][cav_path][2]
- push [bp][cav_path]
- push dx
- push ax
- (*%E *)
- (*%T NearPtr *)
- mov dx, ds
- or ax, ax
- je cav_allocFailed
- mov [bp][cav_bufP][2], dx
- mov [bp][cav_bufP], ax
- push [bp][cav_path]
- push ax
- (*%E *)
- (*%E *)
- (*%T RegParam *)
- (*%F NearPtr *)
- or dx, dx
- je cav_allocFailed
- mov [bp][cav_bufP][2], dx
- mov [bp][cav_bufP], ax
- mov bx, dx
- mov dx, [bp][cav_path][2]
- mov cx, [bp][cav_path]
- (*%E *)
- (*%T NearPtr *)
- mov dx, ds
- or ax, ax
- je cav_allocFailed
- mov [bp][cav_bufP][2], dx
- mov [bp][cav_bufP], ax
- mov bx, [bp][cav_path]
- (*%E *)
- (*%E *)
- (*%F NearCall *)
- call far _strcpy
- (*%E *)
- (*%T NearCall *)
- call _strcpy
- (*%E *)
- (*%F RegParam *)
- (*%F NearPtr *)
- add sp, 8
- (*%E *)
- (*%T NearPtr *)
- add sp, 4
- (*%E *)
- (*%E *)
- cav_copyArgs:
- les di, [bp][cav_bufP]
- add di, si
- mov bx, [bp][cav_argV]
- cav_nextArg:
- mov ds, [bp][cav_argV][2]
- mov ax, ds
- or ax, bx (* is argV == NULL ? *)
- jz cav_terminate
- (*%F NearPtr *)
- add bx, 4 (* next argument *)
- lds si, [bx]
- mov ax, ds
- or ax, si
- jz cav_terminate
- (*%E *)
- (*%T NearPtr *)
- add bx, 2 (* next argument *)
- mov si, [bx]
- or si, si
- jz cav_terminate
- (*%E *)
- mov al, ' '
- stosb
- cav_copyLoop:
- lodsb (* copy argument *)
- or al, al
- jz cav_nextArg
- stosb (* to the new command line *)
- jmp cav_copyLoop
- cav_tooLarge:
- mov ax, E2BIG
- (*%F NearCall *)
- call far __seterrno
- (*%E *)
- (*%T NearCall *)
- call __seterrno
- (*%E *)
- cav_allocFailed:
- sub ax, ax (* return a NULL pointer *)
- cwd
- mov cx, ax (* and a zero length *)
- jmp cav_end
- cav_terminate:
- mov ax, _DATA
- mov ds, ax
- sub al, al
- stosb
- mov cx, di
- (* The argComposite is now complete. *)
- mov ax, [bp][cav_bufP]
- sub cx, ax
- mov dx, es
- cav_end:
- pop es
- pop ds
- pop si
- pop di
- mov sp, bp
- pop bp
- ret 0
- (*****************************************************************************)
- section
- segment _TEXT(CODE,28H)
- segment _DATA(DATA, 28H)
- extrn _getenv
- extrn _strlen
- extrn _malloc
- extrn _free
- extrn __seterrno
- select _DATA
- extrn __env_var
- select _TEXT
- extrn _malloc
- extrn _strlen
- public __CatEnvV :
- (*
- char *_CatEnvV (envV)
- char *envV [];
- The register CX returns the length of the environment string, including
- the terminating zero. CX == 0 in cases of error.
- *)
- cev_envV = sframe
- cev_bufP = -4
- locals = 4
- push bp
- mov bp, sp
- sub sp, locals
- push di
- push si
- push ds
- les si, [bp][cev_envV]
- mov ax, es
- (*%F NearPtr *)
- or ax, si (* is a NULL parameter supplied ? *)
- (*%E *)
- (*%T NearPtr *)
- or si, si
- (*%E *)
- jnz cev_envVset
- mov ax, seg __env_var
- mov es, ax (* if so, return parent's environ. *)
- mov si, __env_var
- mov [bp][cev_envV], si
- mov [bp][cev_envV][2], es
- cev_envVset:
- push es
- pop ds
- sub di, di (* DI = total length of strings *)
- cev_measureNext:
- (*%F NearPtr *)
- les bx, [si]
- add si, 4
- mov ax, es
- or ax, bx
- jz cev_allMeasured
- (*%E *)
- (*%T NearPtr *)
- mov bx, [si]
- add si, 2
- or bx, bx
- jz cev_allMeasured
- (*%E *)
- (*%F RegParam *)
- push es
- push bx
- (*%E *)
- (*%T RegParam *)
- mov ax, bx
- mov bx, es
- (*%E *)
- (*%F NearCall *)
- call far _strlen
- (*%E *)
- (*%T NearCall *)
- call _strlen
- (*%E *)
- (*%F RegParam *)
- add sp, 4
- (*%E *)
- or ax, ax
- jz cev_allMeasured
- add di, ax
- inc di (* plus a terminating \0 *)
- jmp cev_measureNext
- cev_allMeasured:
- inc di (* plus an overall terminator \0 *)
- mov ax, _DATA
- mov ds, ax
- cmp di, 32767-15
- ja cev_tooLarge
- lea ax, [di][0FH] (* allow for paragraph alignment *)
- push ax
- (*%F NearCall *)
- call far _malloc
- (*%E *)
- (*%T NearCall *)
- call _malloc
- (*%E *)
- pop bx
- (*%F NearPtr *)
- or dx, dx
- (*%E *)
- (*%T NearPtr *)
- mov dx, ds
- or ax, ax
- (*%E *)
- jz cev_allocFailed
- mov [bp][cev_bufP][2], dx
- mov [bp][cev_bufP], ax
- (* Now the environment is allocated. Copy the strings into it. *)
- mov es, dx
- mov di, ax
- mov bx, [bp][cev_envV]
- cev_nextArg:
- (*%F NearPtr *)
- mov ds, [bp][cev_envV][2]
- lds si, [bx]
- add bx, 4 (* next string *)
- mov ax, ds
- or ax, si
- jz cev_terminate
- cmp byte [si], 0
- je cev_terminate
- (*%E *)
- (*%T NearPtr *)
- mov si, [bx]
- add bx, 2 (* next string *)
- or si, si
- jz cev_terminate
- cmp byte [si], 0
- je cev_terminate
- (*%E *)
- cev_copyLoop:
- lodsb (* copy string *)
- or al, al
- stosb (* to the new environment *)
- jnz cev_copyLoop
- jmp cev_nextArg
- cev_tooLarge:
- mov ax, E2BIG
- jmp cev_errorRet
- cev_allocFailed:
- mov ax, ENOMEM
- cev_errorRet:
- (*%F NearCall *)
- call far __seterrno
- (*%E *)
- (*%T NearCall *)
- call __seterrno
- (*%E *)
- sub ax, ax (* return a NULL pointer *)
- cwd
- mov cx, -1 (* with zero size. *)
- jmp cev_end
- cev_terminate:
- mov ax, _DATA
- mov ds, ax
- mov al, 0 (* overall terminator zero *)
- stosb
- (* The environment is now complete. *)
- mov ax, [bp][cev_bufP] (* DX:AX = &allocation block *)
- mov dx, [bp][cev_bufP][2] (* ES:0 = &environment. *)
- mov cx, di (* CX = size of environment. *)
- sub cx, ax
- cev_end:
- pop ds
- pop si
- pop di
- mov sp, bp
- pop bp
- ret 0
- (****************************************************************************)
- section
- segment _TEXT(CODE,28H)
- segment _DATA(DATA, 28H)
- extrn _exit
- extrn _free
- extrn __FindProg
- extrn __CatArgV
- extrn __CatEnvV
- extrn __seterrno
- extrn __FloatExecSave
- extrn __FloatExecRestore
- extrn DOSEXECPGM
- select _DATA
- extrn __env
- select _TEXT
- EXEC_SYNC = 0
- EXEC_ASYNC = 1
- EXEC_ASYNCRESULT = 2
- EXEC_TRACE = 3
- EXEC_BACKGROUND = 4
- EXEC_LOAD = 5
- SEARCH = 80H
- P_WAIT = 0
- P_NOWAIT = 1
- P_OVERLAY = 2
- public __beget :
- (*
- int _beget (pathP, argV, envV, flag)
- char *pathP;
- char *argV [];
- char *envV [];
- int flag
- A child process, with program identified by *pathP, is found, validated,
- and executed. The current process continues to exist but is asleep
- until the child process is finished.
- A return value of -1 indicates that the child process could not be
- If usePath is true then the PATH environment variable will be used to
- help find the program name, otherwise *pathP is assumed to include
- directory names and the PATH is not used. However, in either case
- the suffixes ".COM" and ".EXE" will automatically be tried unless
- the supplied name already ends with an extention.
- *)
- codeTerminate = 0
- codeResult = 2
- (*%F RegParam *)
- RetSize = 0
- (*%E *)
- (*%T RegParam *)
- (*%T NearPtr *)
- RetSize = 0
- (*%E *)
- (*%F NearPtr *)
- RetSize = 6
- (*%E *)
- (*%E *)
- (*%F RegParam *)
- path = frame
- (*%F NearPtr *)
- argv = 4+frame
- env = 8+frame
- flag = 12+frame
- (*%E *)
- (*%T NearPtr *)
- argv = 2+frame
- env = 4+frame
- flag = 6+frame
- (*%E *)
- argbuf = -4
- envbuf = -8
- pathbuf = -12
- resbuf = -16
- locals = 16
- (*%E *)
- (*%T RegParam *)
- (*%F NearPtr *)
- flag = frame
- env = 2+frame
- argbuf = -4
- envbuf = -8
- pathbuf = -12
- resbuf = -16
- path = -20
- argv = -24
- locals = 24
- (*%E *)
- (*%T NearPtr *)
- argbuf = -4
- envbuf = -8
- pathbuf = -12
- resbuf = -16
- path = -18
- argv = -20
- env = -22
- flag = -24
- locals = 24
- (*%E *)
- (*%E *)
- push bp
- mov bp, sp
- sub sp, locals
- call far __FloatExecSave
- (*%T RegParam *)
- (*%F NearPtr *)
- mov [bp][path], ax
- mov [bp][path][2], bx
- mov [bp][argv], cx
- mov [bp][argv][2], dx
- (*%E *)
- (*%T NearPtr *)
- mov [bp][path], ax
- mov [bp][argv], bx
- mov [bp][env], cx
- mov [bp][flag], dx
- (*%E *)
- (*%E *)
- push di
- push si
- (*%F SameDS *)
- push ds
- mov ax, seg __env
- mov ds, ax
- (*%E *)
- (*%F NearPtr *)
- push [bp][path][2]
- (*%E *)
- (*%T NearPtr *)
- push ds
- (*%E *)
- push [bp][path]
- mov ax, [bp][flag]
- and ax, SEARCH
- push ax
- call __FindProg
- add sp, 6
- jcxz near notFound
- mov [bp][pathbuf][2], dx
- mov [bp][pathbuf], ax
- push dx
- push ax
- (*%F NearPtr *)
- push [bp][argv][2]
- (*%E *)
- (*%T NearPtr *)
- push ds
- (*%E *)
- push [bp][argv]
- call __CatArgV
- add sp, 8
- jcxz near badargv
- mov [bp][argbuf][2], dx
- mov [bp][argbuf], ax
- (*%F NearPtr *)
- push [bp][env][2]
- (*%E *)
- (*%T NearPtr *)
- push ds
- (*%E *)
- push [bp][env]
- call __CatEnvV
- add sp, 4
- cmp cx, -1
- je near badenv
- mov [bp][envbuf][2], dx
- mov [bp][envbuf], ax
- mov ax, [bp][flag]
- and ax, ~SEARCH
- mov [bp][flag], ax
- call __selectmode
- cmp ax, -1
- je badMode
- sub bx, bx
- push bx
- push bx
- push bx
- push ax
- push [bp][argbuf][2]
- push [bp][argbuf]
- mov ax, [bp][envbuf][2]
- or ax, ax
- jnz envNew
- mov ax, [__env]
- sub bx, bx
- jmp envSet
- envNew:
- mov bx, [bp][envbuf]
- envSet:
- push ax
- push bx
- push ss
- lea ax, [bp][resbuf]
- push ax
- push [bp][pathbuf][2]
- push [bp][pathbuf]
- call far DOSEXECPGM
- or ax, ax
- jnz begetError
- mov ax, [bp][flag]
- cmp ax, P_OVERLAY
- je terminate
- cmp ax, P_WAIT
- je getRetcode
- mov si, [bp][resbuf][codeTerminate] (* child's PID *)
- jmp begetDone
- getRetcode: (* child's return code *)
- mov si, [bp][resbuf][codeResult]
- begetDone:
- call __freeenv
- call __freeargv
- call __freepath
- mov ax, si
- begetExit:
- (*%F SameDS *)
- pop ds
- (*%E *)
- pop si
- pop di
- call far __FloatExecRestore
- mov sp, bp
- pop bp
- (*%F NearCall *)
- ret far RetSize
- (*%E *)
- (*%T NearCall *)
- ret RetSize
- (*%E *)
- terminate:
- sub ax, ax
- (*%F RegParam *)
- push ax
- (*%E *)
- (*%F NearCall *)
- call far _exit
- (*%E *)
- (*%T NearCall *)
- call _exit
- (*%E *)
- badMode:
- call __freepath
- call __freeargv
- call __freeenv
- mov ax, EINVAL
- jmp begetError
- notFound:
- mov ax, ENOPATH
- jmp begetError
- badargv:
- call __freepath
- mov ax, E2BIG
- jmp begetError
- badenv:
- call __freepath
- call __freeargv
- mov ax, E2BIG
- jmp begetError
- begetError:
- (*%F NearCall *)
- call far __seterrno
- (*%E *)
- (*%T NearCall *)
- call __seterrno
- (*%E *)
- mov ax, -1
- jmp begetExit
- __freepath :
- (*%F RegParam *)
- push [bp][pathbuf][2]
- push [bp][pathbuf]
- (*%E *)
- (*%T RegParam *)
- mov bx, [bp][pathbuf][2]
- mov ax, [bp][pathbuf]
- (*%E *)
- (*%F NearCall *)
- call far _free
- (*%E *)
- (*%T NearCall *)
- call _free
- (*%E *)
- (*%F RegParam *)
- add sp, 4
- (*%E *)
- ret 0
- __freeargv :
- (*%F RegParam *)
- push [bp][argbuf][2]
- push [bp][argbuf]
- (*%E *)
- (*%T RegParam *)
- mov bx, [bp][argbuf][2]
- mov ax, [bp][argbuf]
- (*%E *)
- (*%F NearCall *)
- call far _free
- (*%E *)
- (*%T NearCall *)
- call _free
- (*%E *)
- (*%F RegParam *)
- add sp, 4
- (*%E *)
- ret 0
- __freeenv :
- mov cx, [bp][envbuf][2]
- jcxz dontFree
- (*%F RegParam *)
- push cx
- push [bp][envbuf]
- (*%E *)
- (*%T RegParam *)
- mov bx, cx
- mov ax, [bp][envbuf]
- (*%E *)
- (*%F NearCall *)
- call far _free
- (*%E *)
- (*%T NearCall *)
- call _free
- (*%E *)
- (*%F RegParam *)
- add sp, 4
- (*%E *)
- dontFree:
- ret 0
- __selectmode :
- cmp ax, P_WAIT
- jne s1
- mov ax, EXEC_SYNC
- jmp done
- s1:
- cmp ax, P_NOWAIT
- jne s2
- mov ax, EXEC_ASYNC
- jmp done
- s2:
- cmp ax, P_OVERLAY
- jne serr
- mov ax, EXEC_ASYNC
- jmp done
- serr:
- mov ax, -1
- done:
- ret 0
- section
- segment _TEXT(CODE,28H)
- select _TEXT
- $init:
- (*%T NearCall*)
- ret near 0
- (*%E*)
- (*%F NearCall*)
- ret far 0
- (*%E*)
- segment _DATA(DATA,00028H)
- public SPAWN$:
- (*%T NearCall*)
- dw $init
- (*%E*)
- (*%F NearCall*)
- dd $init
- (*%E*)
- dw -1
- (*%E *)
- end
|