parser.c 81 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. parser.c
  5. Abstract:
  6. This module implements the shell grammar parser.
  7. Author:
  8. Evan Green 5-Jun-2013
  9. Environment:
  10. User Mode
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include "sh.h"
  16. #include "shparse.h"
  17. #include "../swlib.h"
  18. #include <stdarg.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <unistd.h>
  22. #include <assert.h>
  23. //
  24. // ---------------------------------------------------------------- Definitions
  25. //
  26. //
  27. // ------------------------------------------------------ Data Type Definitions
  28. //
  29. //
  30. // ----------------------------------------------- Internal Function Prototypes
  31. //
  32. BOOL
  33. ShParseCompleteCommand (
  34. PSHELL Shell,
  35. PSHELL_NODE *CompleteCommandNode
  36. );
  37. PSHELL_NODE
  38. ShParseList (
  39. PSHELL Shell
  40. );
  41. PSHELL_NODE
  42. ShParseAndOr (
  43. PSHELL Shell
  44. );
  45. PSHELL_NODE
  46. ShParsePipeline (
  47. PSHELL Shell
  48. );
  49. PSHELL_NODE
  50. ShParseCommand (
  51. PSHELL Shell
  52. );
  53. PSHELL_NODE
  54. ShParseCompoundCommand (
  55. PSHELL Shell
  56. );
  57. PSHELL_NODE
  58. ShParseBraceGroup (
  59. PSHELL Shell
  60. );
  61. PSHELL_NODE
  62. ShParseSubshell (
  63. PSHELL Shell
  64. );
  65. PSHELL_NODE
  66. ShParseIf (
  67. PSHELL Shell
  68. );
  69. PSHELL_NODE
  70. ShParseWhileOrUntil (
  71. PSHELL Shell
  72. );
  73. PSHELL_NODE
  74. ShParseFor (
  75. PSHELL Shell
  76. );
  77. PSHELL_NODE
  78. ShParseCase (
  79. PSHELL Shell
  80. );
  81. BOOL
  82. ShParsePattern (
  83. PSHELL Shell,
  84. PSHELL_NODE Case,
  85. PSHELL_CASE_PATTERN_SET *NewPatternSet
  86. );
  87. PSHELL_NODE
  88. ShParseDoGroup (
  89. PSHELL Shell
  90. );
  91. PSHELL_NODE
  92. ShParseCompoundList (
  93. PSHELL Shell
  94. );
  95. PSHELL_NODE
  96. ShParseTerm (
  97. PSHELL Shell
  98. );
  99. PSHELL_NODE
  100. ShParseSimpleCommandOrFunction (
  101. PSHELL Shell
  102. );
  103. PSHELL_NODE
  104. ShParseSimpleCommand (
  105. PSHELL Shell,
  106. PSTR FirstWord,
  107. UINTN FirstWordSize
  108. );
  109. PSHELL_NODE
  110. ShParseFunctionDefinition (
  111. PSHELL Shell,
  112. PSTR FunctionName,
  113. UINTN FunctionNameSize
  114. );
  115. BOOL
  116. ShParseOptionalRedirectList (
  117. PSHELL Shell,
  118. PSHELL_NODE Node
  119. );
  120. BOOL
  121. ShParseRedirection (
  122. PSHELL Shell,
  123. PSHELL_NODE Node
  124. );
  125. BOOL
  126. ShParseAssignment (
  127. PSHELL Shell,
  128. PSHELL_NODE Node
  129. );
  130. BOOL
  131. ShParseLineBreak (
  132. PSHELL Shell,
  133. BOOL Required,
  134. BOOL FirstCommandWord
  135. );
  136. BOOL
  137. ShParseSeparator (
  138. PSHELL Shell,
  139. PCHAR Separator
  140. );
  141. BOOL
  142. ShParseSeparatorOp (
  143. PSHELL Shell,
  144. PCHAR Separator
  145. );
  146. PSHELL_NODE
  147. ShCreateNode (
  148. PSHELL Shell,
  149. SHELL_NODE_TYPE Type
  150. );
  151. VOID
  152. ShDeleteNode (
  153. PSHELL_NODE Node
  154. );
  155. VOID
  156. ShPrintNode (
  157. PSHELL Shell,
  158. PSHELL_NODE Node,
  159. ULONG Depth
  160. );
  161. BOOL
  162. ShCreateRedirection (
  163. PSHELL Shell,
  164. PSHELL_NODE Node,
  165. SHELL_IO_REDIRECTION_TYPE Type,
  166. INT FileNumber,
  167. PSTR FileName,
  168. UINTN FileNameSize
  169. );
  170. VOID
  171. ShDestroyRedirection (
  172. PSHELL_IO_REDIRECT Redirect
  173. );
  174. BOOL
  175. ShCreateAssignment (
  176. PSHELL_NODE Node,
  177. PSTR Name,
  178. UINTN NameSize,
  179. PSTR Value,
  180. UINTN ValueSize
  181. );
  182. VOID
  183. ShDestroyAssignment (
  184. PSHELL_ASSIGNMENT Assignment
  185. );
  186. BOOL
  187. ShAddPatternToSet (
  188. PSHELL_CASE_PATTERN_SET Set,
  189. PSTR Pattern,
  190. UINTN PatternSize
  191. );
  192. VOID
  193. ShDestroyCasePatternList (
  194. PSHELL_NODE CaseNode
  195. );
  196. BOOL
  197. ShAddComponentToCommand (
  198. PSHELL_NODE Command,
  199. PSTR Component,
  200. UINTN ComponentSize
  201. );
  202. BOOL
  203. ShIsStringQuoted (
  204. PSTR String
  205. );
  206. VOID
  207. ShParseError (
  208. PSHELL Shell,
  209. PSHELL_NODE Node,
  210. PSTR Format,
  211. ...
  212. );
  213. //
  214. // -------------------------------------------------------------------- Globals
  215. //
  216. BOOL ShDebugPrintParseTree = FALSE;
  217. //
  218. // ------------------------------------------------------------------ Functions
  219. //
  220. BOOL
  221. ShParse (
  222. PSHELL Shell,
  223. PSHELL_NODE *Node
  224. )
  225. /*++
  226. Routine Description:
  227. This routine attempts to parse a complete command out of the shell input.
  228. Arguments:
  229. Shell - Supplies a pointer to the shell object.
  230. Node - Supplies a pointer where the parsed node representing the command
  231. will be returned.
  232. Return Value:
  233. TRUE on success.
  234. FALSE on failure.
  235. --*/
  236. {
  237. PSHELL_NODE Command;
  238. BOOL Result;
  239. Command = NULL;
  240. //
  241. // Prime the lexer.
  242. //
  243. if (Shell->Lexer.LexerPrimed == FALSE) {
  244. Result = ShGetToken(Shell, TRUE);
  245. if (Result == FALSE) {
  246. goto ParseEnd;
  247. }
  248. Shell->Lexer.LexerPrimed = TRUE;
  249. }
  250. Result = ShParseCompleteCommand(Shell, &Command);
  251. if ((Result == FALSE) &&
  252. ((Shell->Options & SHELL_OPTION_INTERACTIVE) == 0)) {
  253. PRINT_ERROR("sh: Failed to parse command.\n");
  254. }
  255. if ((Command != NULL) && (ShDebugPrintParseTree != FALSE)) {
  256. ShPrintNode(Shell, Command, 0);
  257. }
  258. ParseEnd:
  259. *Node = Command;
  260. return Result;
  261. }
  262. VOID
  263. ShDestroyHereDocument (
  264. PSHELL_HERE_DOCUMENT HereDocument
  265. )
  266. /*++
  267. Routine Description:
  268. This routine destroys a here document. It assumes the here document is
  269. already removed from any list it was on.
  270. Arguments:
  271. HereDocument - Supplies a pointer to the here document to destroy.
  272. Return Value:
  273. None.
  274. --*/
  275. {
  276. if (HereDocument->EndWord != NULL) {
  277. free(HereDocument->EndWord);
  278. }
  279. if (HereDocument->Document != NULL) {
  280. free(HereDocument->Document);
  281. }
  282. free(HereDocument);
  283. return;
  284. }
  285. VOID
  286. ShRetainNode (
  287. PSHELL_NODE Node
  288. )
  289. /*++
  290. Routine Description:
  291. This routine increases the reference count on a node.
  292. Arguments:
  293. Node - Supplies a pointer to the node to retain.
  294. Return Value:
  295. None.
  296. --*/
  297. {
  298. assert((Node->ReferenceCount > 0) && (Node->ReferenceCount < 0x1000));
  299. Node->ReferenceCount += 1;
  300. return;
  301. }
  302. VOID
  303. ShReleaseNode (
  304. PSHELL_NODE Node
  305. )
  306. /*++
  307. Routine Description:
  308. This routine releases a reference on a shell node. If this causes the
  309. reference count to drop to zero then the node is destroyed.
  310. Arguments:
  311. Node - Supplies a pointer to the node to release.
  312. Return Value:
  313. None.
  314. --*/
  315. {
  316. assert((Node->ReferenceCount > 0) && (Node->ReferenceCount < 0x1000));
  317. Node->ReferenceCount -= 1;
  318. if (Node->ReferenceCount == 0) {
  319. ShDeleteNode(Node);
  320. }
  321. return;
  322. }
  323. BOOL
  324. ShIsName (
  325. PSTR String,
  326. UINTN StringSize
  327. )
  328. /*++
  329. Routine Description:
  330. This routine determines if the given string is a valid NAME according to
  331. the shell grammar.
  332. Arguments:
  333. String - Supplies a pointer to the candidate string.
  334. StringSize - Supplies the number of characters to check.
  335. Return Value:
  336. TRUE if the string is a valid name.
  337. FALSE if the string is not a valid name.
  338. --*/
  339. {
  340. UCHAR Character;
  341. ULONG Index;
  342. if (StringSize == 0) {
  343. return FALSE;
  344. }
  345. //
  346. // The first character can be A through Z or an underscore.
  347. //
  348. Character = *String;
  349. if (!SHELL_NAME_FIRST_CHARACTER(Character)) {
  350. return FALSE;
  351. }
  352. for (Index = 1; Index < StringSize; Index += 1) {
  353. Character = String[Index];
  354. if (Character == '\0') {
  355. break;
  356. }
  357. if (!SHELL_NAME_CHARACTER(Character)) {
  358. return FALSE;
  359. }
  360. }
  361. return TRUE;
  362. }
  363. //
  364. // --------------------------------------------------------- Internal Functions
  365. //
  366. BOOL
  367. ShParseCompleteCommand (
  368. PSHELL Shell,
  369. PSHELL_NODE *CompleteCommandNode
  370. )
  371. /*++
  372. Routine Description:
  373. This routine attempts to parse a complete command out of the shell input.
  374. Arguments:
  375. Shell - Supplies a pointer to the shell object.
  376. CompleteCommandNode - Supplies a pointer where the complete command will
  377. be returned on success. The caller is responsible for destroying this
  378. node.
  379. Return Value:
  380. TRUE on success.
  381. FALSE on failure.
  382. --*/
  383. {
  384. PSHELL_NODE List;
  385. BOOL Result;
  386. CHAR SeparatorOp;
  387. Result = FALSE;
  388. List = NULL;
  389. //
  390. // Get rid of any extraneous newlines.
  391. //
  392. while (Shell->Lexer.TokenType == '\n') {
  393. ShCheckForSignals(Shell);
  394. ShPrintPrompt(Shell, 1);
  395. Result = ShGetToken(Shell, TRUE);
  396. if (Result == FALSE) {
  397. goto ParseCompleteCommandEnd;
  398. }
  399. }
  400. if (Shell->Lexer.TokenType == TOKEN_END_OF_FILE) {
  401. Result = TRUE;
  402. goto ParseCompleteCommandEnd;
  403. }
  404. List = ShParseList(Shell);
  405. if (List == NULL) {
  406. Result = FALSE;
  407. goto ParseCompleteCommandEnd;
  408. }
  409. Result = ShParseSeparatorOp(Shell, &SeparatorOp);
  410. if ((Result != FALSE) && (SeparatorOp == '&')) {
  411. List->RunInBackground = TRUE;
  412. }
  413. Result = TRUE;
  414. ParseCompleteCommandEnd:
  415. if (Result == FALSE) {
  416. if (List != NULL) {
  417. ShReleaseNode(List);
  418. List = NULL;
  419. }
  420. }
  421. *CompleteCommandNode = List;
  422. return Result;
  423. }
  424. PSHELL_NODE
  425. ShParseList (
  426. PSHELL Shell
  427. )
  428. /*++
  429. Routine Description:
  430. This routine attempts to parse a list out of the shell input.
  431. Arguments:
  432. Shell - Supplies a pointer to the shell object.
  433. Return Value:
  434. Returns a pointer to the node on success.
  435. NULL on failure.
  436. --*/
  437. {
  438. PSHELL_NODE AndOr;
  439. PSHELL_NODE List;
  440. BOOL Result;
  441. CHAR SeparatorOp;
  442. Result = FALSE;
  443. List = NULL;
  444. //
  445. // Parse and-or statements separated by separator operators.
  446. //
  447. while (TRUE) {
  448. AndOr = ShParseAndOr(Shell);
  449. if (AndOr == NULL) {
  450. if (List == NULL) {
  451. Result = FALSE;
  452. ShParseError(Shell, NULL, "Unexpected token.");
  453. goto ParseListEnd;
  454. }
  455. break;
  456. }
  457. Result = ShParseSeparatorOp(Shell, &SeparatorOp);
  458. //
  459. // If this is the first time around and there's only one item, then
  460. // just return that item.
  461. //
  462. if ((Result == FALSE) && (List == NULL)) {
  463. List = AndOr;
  464. break;
  465. }
  466. //
  467. // There's more than one and-or. If the listhas yet to be made, make it
  468. // now.
  469. //
  470. if (List == NULL) {
  471. List = ShCreateNode(Shell, ShellNodeList);
  472. if (List == NULL) {
  473. goto ParseListEnd;
  474. }
  475. }
  476. INSERT_BEFORE(&(AndOr->SiblingListEntry), &(List->Children));
  477. //
  478. // Regardless of where the command was, if there's no separator, this
  479. // loop is done.
  480. //
  481. if (Result == FALSE) {
  482. break;
  483. }
  484. if (SeparatorOp == '&') {
  485. AndOr->RunInBackground = TRUE;
  486. }
  487. }
  488. AndOr = NULL;
  489. Result = TRUE;
  490. ParseListEnd:
  491. if (AndOr != NULL) {
  492. ShReleaseNode(AndOr);
  493. }
  494. if (Result == FALSE) {
  495. if (List != NULL) {
  496. ShReleaseNode(List);
  497. List = NULL;
  498. }
  499. }
  500. return List;
  501. }
  502. PSHELL_NODE
  503. ShParseAndOr (
  504. PSHELL Shell
  505. )
  506. /*++
  507. Routine Description:
  508. This routine attempts to parse an and-or statement out of the shell input.
  509. Arguments:
  510. Shell - Supplies a pointer to the shell object.
  511. Return Value:
  512. Returns a pointer to the node on success.
  513. NULL on failure.
  514. --*/
  515. {
  516. PSHELL_NODE AndOr;
  517. PSHELL_NODE Pipeline;
  518. BOOL Result;
  519. ULONG SeparatorToken;
  520. Result = FALSE;
  521. AndOr = NULL;
  522. //
  523. // Parse pipeline statements separated by separator operators.
  524. //
  525. while (TRUE) {
  526. Pipeline = ShParsePipeline(Shell);
  527. if (Pipeline == NULL) {
  528. goto ParseAndOrEnd;
  529. }
  530. SeparatorToken = Shell->Lexer.TokenType;
  531. //
  532. // If this is the first time around and there's only one item, then
  533. // just return that item.
  534. //
  535. if ((SeparatorToken != TOKEN_DOUBLE_AND) &&
  536. (SeparatorToken != TOKEN_DOUBLE_OR) &&
  537. (AndOr == NULL)) {
  538. AndOr = Pipeline;
  539. break;
  540. }
  541. //
  542. // There's more than one pipeline. If the and-or has yet to be
  543. // made, make it now.
  544. //
  545. if (AndOr == NULL) {
  546. AndOr = ShCreateNode(Shell, ShellNodeAndOr);
  547. if (AndOr == NULL) {
  548. goto ParseAndOrEnd;
  549. }
  550. }
  551. INSERT_BEFORE(&(Pipeline->SiblingListEntry), &(AndOr->Children));
  552. //
  553. // Regardless of where the pipeline was, if there's no valid AND or OR,
  554. // stop.
  555. //
  556. if ((SeparatorToken != TOKEN_DOUBLE_AND) &&
  557. (SeparatorToken != TOKEN_DOUBLE_OR)) {
  558. break;
  559. }
  560. Pipeline->AndOr = SeparatorToken;
  561. Pipeline = NULL;
  562. Result = ShGetToken(Shell, TRUE);
  563. if (Result == FALSE) {
  564. goto ParseAndOrEnd;
  565. }
  566. Result = ShParseLineBreak(Shell, FALSE, TRUE);
  567. if (Result == FALSE) {
  568. goto ParseAndOrEnd;
  569. }
  570. }
  571. Pipeline = NULL;
  572. Result = TRUE;
  573. ParseAndOrEnd:
  574. if (Pipeline != NULL) {
  575. ShReleaseNode(Pipeline);
  576. }
  577. if (Result == FALSE) {
  578. if (AndOr != NULL) {
  579. ShReleaseNode(AndOr);
  580. AndOr = NULL;
  581. }
  582. }
  583. return AndOr;
  584. }
  585. PSHELL_NODE
  586. ShParsePipeline (
  587. PSHELL Shell
  588. )
  589. /*++
  590. Routine Description:
  591. This routine attempts to parse a pipeline out of the shell input.
  592. Arguments:
  593. Shell - Supplies a pointer to the shell object.
  594. Return Value:
  595. Returns a pointer to the node on success.
  596. NULL on failure.
  597. --*/
  598. {
  599. PSHELL_NODE Command;
  600. PSHELL_NODE Pipeline;
  601. BOOL Result;
  602. Command = NULL;
  603. Pipeline = NULL;
  604. Result = FALSE;
  605. //
  606. // Parse an optional ! at the beginning.
  607. //
  608. if (Shell->Lexer.TokenType == '!') {
  609. Pipeline = ShCreateNode(Shell, ShellNodePipeline);
  610. if (Pipeline == NULL) {
  611. goto ParsePipelineEnd;
  612. }
  613. Pipeline->U.Pipeline.Bang = TRUE;
  614. Result = ShGetToken(Shell, TRUE);
  615. if (Result == FALSE) {
  616. goto ParsePipelineEnd;
  617. }
  618. }
  619. //
  620. // Parse pipeline statements separated by separator operators.
  621. //
  622. while (TRUE) {
  623. Command = ShParseCommand(Shell);
  624. if (Command == NULL) {
  625. Result = FALSE;
  626. goto ParsePipelineEnd;
  627. }
  628. //
  629. // If this is the first time around and there's only one item, then
  630. // just return that item.
  631. //
  632. if ((Shell->Lexer.TokenType != '|') && (Pipeline == NULL)) {
  633. Pipeline = Command;
  634. break;
  635. }
  636. //
  637. // There's more than one command. If the pipeline has yet to be made,
  638. // make it now.
  639. //
  640. if (Pipeline == NULL) {
  641. Pipeline = ShCreateNode(Shell, ShellNodePipeline);
  642. if (Pipeline == NULL) {
  643. goto ParsePipelineEnd;
  644. }
  645. }
  646. INSERT_BEFORE(&(Command->SiblingListEntry), &(Pipeline->Children));
  647. //
  648. // Regardless of where the command was, if there's no valid pipe
  649. // character then stop. Otherwise, move over the pipe character.
  650. //
  651. if (Shell->Lexer.TokenType != '|') {
  652. break;
  653. }
  654. Result = ShGetToken(Shell, TRUE);
  655. if (Result == FALSE) {
  656. Command = NULL;
  657. goto ParsePipelineEnd;
  658. }
  659. //
  660. // It's known now that most recent command wasn't the last, so set it
  661. // to run in the background so the shell doesn't wait on it.
  662. //
  663. Command->RunInBackground = TRUE;
  664. ShParseLineBreak(Shell, FALSE, TRUE);
  665. }
  666. Command = NULL;
  667. Result = TRUE;
  668. ParsePipelineEnd:
  669. if (Command != NULL) {
  670. ShReleaseNode(Command);
  671. }
  672. if (Result == FALSE) {
  673. if (Pipeline != NULL) {
  674. ShReleaseNode(Pipeline);
  675. Pipeline = NULL;
  676. }
  677. }
  678. return Pipeline;
  679. }
  680. PSHELL_NODE
  681. ShParseCommand (
  682. PSHELL Shell
  683. )
  684. /*++
  685. Routine Description:
  686. This routine attempts to parse a command.
  687. Arguments:
  688. Shell - Supplies a pointer to the shell object.
  689. Return Value:
  690. Returns a pointer to the node on success.
  691. NULL on failure.
  692. --*/
  693. {
  694. PSHELL_NODE Command;
  695. //
  696. // A command is either a simple command, compound command, or function
  697. // definition.
  698. //
  699. switch (Shell->Lexer.TokenType) {
  700. case '{':
  701. case '(':
  702. case TOKEN_FOR:
  703. case TOKEN_CASE:
  704. case TOKEN_IF:
  705. case TOKEN_WHILE:
  706. case TOKEN_UNTIL:
  707. Command = ShParseCompoundCommand(Shell);
  708. break;
  709. case TOKEN_ASSIGNMENT_WORD:
  710. case TOKEN_IO_NUMBER:
  711. case TOKEN_LESS_THAN_AND:
  712. case TOKEN_GREATER_THAN_AND:
  713. case TOKEN_DOUBLE_GREATER_THAN:
  714. case TOKEN_DOUBLE_LESS_THAN:
  715. case TOKEN_DOUBLE_LESS_THAN_DASH:
  716. case '>':
  717. case '<':
  718. Command = ShParseSimpleCommand(Shell, NULL, 0);
  719. break;
  720. case TOKEN_WORD:
  721. Command = ShParseSimpleCommandOrFunction(Shell);
  722. break;
  723. default:
  724. Command = NULL;
  725. break;
  726. }
  727. return Command;
  728. }
  729. PSHELL_NODE
  730. ShParseCompoundCommand (
  731. PSHELL Shell
  732. )
  733. /*++
  734. Routine Description:
  735. This routine attempts to parse a command.
  736. Arguments:
  737. Shell - Supplies a pointer to the shell object.
  738. Return Value:
  739. Returns a pointer to the node on success.
  740. NULL on failure.
  741. --*/
  742. {
  743. PSHELL_NODE Command;
  744. BOOL Result;
  745. Command = NULL;
  746. Result = TRUE;
  747. //
  748. // A command is either a simple command, compound command, or function
  749. // definition.
  750. //
  751. switch (Shell->Lexer.TokenType) {
  752. case '{':
  753. Command = ShParseBraceGroup(Shell);
  754. break;
  755. case '(':
  756. Command = ShParseSubshell(Shell);
  757. break;
  758. case TOKEN_FOR:
  759. Command = ShParseFor(Shell);
  760. break;
  761. case TOKEN_CASE:
  762. Command = ShParseCase(Shell);
  763. break;
  764. case TOKEN_IF:
  765. Command = ShParseIf(Shell);
  766. break;
  767. case TOKEN_WHILE:
  768. case TOKEN_UNTIL:
  769. Command = ShParseWhileOrUntil(Shell);
  770. break;
  771. default:
  772. ShParseError(Shell, NULL, "Unexpected token for compound command.");
  773. break;
  774. }
  775. if (Command == NULL) {
  776. return NULL;
  777. }
  778. //
  779. // Compound commands can optionally have a redirect list on them too.
  780. //
  781. Result = ShParseOptionalRedirectList(Shell, Command);
  782. if (Result == FALSE) {
  783. goto ParseCompoundCommandEnd;
  784. }
  785. ParseCompoundCommandEnd:
  786. if (Result == FALSE) {
  787. if (Command != NULL) {
  788. ShReleaseNode(Command);
  789. Command = NULL;
  790. }
  791. }
  792. return Command;
  793. }
  794. PSHELL_NODE
  795. ShParseBraceGroup (
  796. PSHELL Shell
  797. )
  798. /*++
  799. Routine Description:
  800. This routine attempts to parse a set of statements surrounded by a brace
  801. group.
  802. Arguments:
  803. Shell - Supplies a pointer to the shell object.
  804. Return Value:
  805. Returns a pointer to the node on success.
  806. NULL on failure.
  807. --*/
  808. {
  809. PSHELL_NODE BraceGroup;
  810. PSHELL_NODE CompoundList;
  811. BOOL Result;
  812. //
  813. // Scan over the open brace.
  814. //
  815. assert(Shell->Lexer.TokenType == '{');
  816. BraceGroup = ShCreateNode(Shell, ShellNodeBraceGroup);
  817. if (BraceGroup == NULL) {
  818. Result = FALSE;
  819. goto ParseBraceGroupEnd;
  820. }
  821. Result = ShGetToken(Shell, TRUE);
  822. if (Result == FALSE) {
  823. goto ParseBraceGroupEnd;
  824. }
  825. //
  826. // Get the tender compound list inside.
  827. //
  828. CompoundList = ShParseCompoundList(Shell);
  829. if (CompoundList == NULL) {
  830. Result = FALSE;
  831. goto ParseBraceGroupEnd;
  832. }
  833. INSERT_BEFORE(&(CompoundList->SiblingListEntry), &(BraceGroup->Children));
  834. //
  835. // Scan over the closing brace.
  836. //
  837. if (Shell->Lexer.TokenType != '}') {
  838. ShParseError(Shell,
  839. NULL,
  840. "Expected '}' for open brace at line %d.",
  841. BraceGroup->LineNumber);
  842. Result = FALSE;
  843. goto ParseBraceGroupEnd;
  844. }
  845. Result = ShGetToken(Shell, TRUE);
  846. if (Result == FALSE) {
  847. goto ParseBraceGroupEnd;
  848. }
  849. ParseBraceGroupEnd:
  850. if (Result == FALSE) {
  851. if (BraceGroup != NULL) {
  852. ShReleaseNode(BraceGroup);
  853. BraceGroup = NULL;
  854. }
  855. }
  856. return BraceGroup;
  857. }
  858. PSHELL_NODE
  859. ShParseSubshell (
  860. PSHELL Shell
  861. )
  862. /*++
  863. Routine Description:
  864. This routine attempts to parse a subshell sequence, which is basically of
  865. the form ( compound list ).
  866. Arguments:
  867. Shell - Supplies a pointer to the shell object.
  868. Return Value:
  869. Returns a pointer to the node on success.
  870. NULL on failure.
  871. --*/
  872. {
  873. PSHELL_NODE CompoundList;
  874. PSHELL_NODE Node;
  875. BOOL Result;
  876. Node = ShCreateNode(Shell, ShellNodeSubshell);
  877. if (Node == NULL) {
  878. Result = FALSE;
  879. goto ParseSubshellEnd;
  880. }
  881. assert(Shell->Lexer.TokenType == '(');
  882. Result = ShGetToken(Shell, TRUE);
  883. if (Result == FALSE) {
  884. goto ParseSubshellEnd;
  885. }
  886. CompoundList = ShParseCompoundList(Shell);
  887. if (CompoundList == NULL) {
  888. Result = FALSE;
  889. goto ParseSubshellEnd;
  890. }
  891. INSERT_BEFORE(&(CompoundList->SiblingListEntry), &(Node->Children));
  892. if (Shell->Lexer.TokenType != ')') {
  893. ShParseError(Shell,
  894. NULL,
  895. "Expected ')' for subshell at line %d.",
  896. Node->LineNumber);
  897. Result = FALSE;
  898. goto ParseSubshellEnd;
  899. }
  900. Result = ShGetToken(Shell, TRUE);
  901. if (Result == FALSE) {
  902. goto ParseSubshellEnd;
  903. }
  904. Result = TRUE;
  905. ParseSubshellEnd:
  906. if (Result == FALSE) {
  907. if (Node != NULL) {
  908. ShReleaseNode(Node);
  909. Node = NULL;
  910. }
  911. }
  912. return Node;
  913. }
  914. PSHELL_NODE
  915. ShParseIf (
  916. PSHELL Shell
  917. )
  918. /*++
  919. Routine Description:
  920. This routine attempts to parse an if statement.
  921. Arguments:
  922. Shell - Supplies a pointer to the shell object.
  923. Return Value:
  924. Returns a pointer to the node on success.
  925. NULL on failure.
  926. --*/
  927. {
  928. PSHELL_NODE Condition;
  929. PSHELL_NODE ElseBody;
  930. PSHELL_NODE Node;
  931. BOOL Result;
  932. BOOL SwallowFi;
  933. PSHELL_NODE ThenCompoundList;
  934. assert((Shell->Lexer.TokenType == TOKEN_IF) ||
  935. (Shell->Lexer.TokenType == TOKEN_ELIF));
  936. //
  937. // Don't swallow the "fi" if this is an elif.
  938. //
  939. SwallowFi = TRUE;
  940. if (Shell->Lexer.TokenType == TOKEN_ELIF) {
  941. SwallowFi = FALSE;
  942. }
  943. Node = NULL;
  944. Result = ShGetToken(Shell, TRUE);
  945. if (Result == FALSE) {
  946. goto ParseIfEnd;
  947. }
  948. Node = ShCreateNode(Shell, ShellNodeIf);
  949. if (Node == NULL) {
  950. Result = FALSE;
  951. goto ParseIfEnd;
  952. }
  953. //
  954. // Parse out the condition part of the if statement.
  955. //
  956. Condition = ShParseCompoundList(Shell);
  957. if (Condition == NULL) {
  958. Result = FALSE;
  959. goto ParseIfEnd;
  960. }
  961. INSERT_BEFORE(&(Condition->SiblingListEntry), &(Node->Children));
  962. //
  963. // The next thing had better be a "then".
  964. //
  965. if (Shell->Lexer.TokenType != TOKEN_THEN) {
  966. ShParseError(Shell,
  967. NULL,
  968. "Expected 'then' for if at line %d.",
  969. Node->LineNumber);
  970. Result = FALSE;
  971. goto ParseIfEnd;
  972. }
  973. Result = ShGetToken(Shell, TRUE);
  974. if (Result == FALSE) {
  975. goto ParseIfEnd;
  976. }
  977. //
  978. // Parse the compound list of stuff to do if the condition succeeds.
  979. //
  980. ThenCompoundList = ShParseCompoundList(Shell);
  981. if (ThenCompoundList == NULL) {
  982. Result = FALSE;
  983. goto ParseIfEnd;
  984. }
  985. INSERT_BEFORE(&(ThenCompoundList->SiblingListEntry), &(Node->Children));
  986. //
  987. // Ok, so there's an else or elif. If it's an else, parse out the
  988. // compound list that follows. For elifs, pretend it's a brand new if
  989. // statement inside the else.
  990. //
  991. if ((Shell->Lexer.TokenType == TOKEN_ELSE) ||
  992. (Shell->Lexer.TokenType == TOKEN_ELIF)) {
  993. if (Shell->Lexer.TokenType == TOKEN_ELSE) {
  994. Result = ShGetToken(Shell, TRUE);
  995. if (Result == FALSE) {
  996. goto ParseIfEnd;
  997. }
  998. ElseBody = ShParseCompoundList(Shell);
  999. } else {
  1000. ElseBody = ShParseIf(Shell);
  1001. }
  1002. if (ElseBody == NULL) {
  1003. Result = FALSE;
  1004. goto ParseIfEnd;
  1005. }
  1006. INSERT_BEFORE(&(ElseBody->SiblingListEntry), &(Node->Children));
  1007. }
  1008. //
  1009. // There had better be a fi at the end.
  1010. //
  1011. if (Shell->Lexer.TokenType != TOKEN_FI) {
  1012. ShParseError(Shell,
  1013. NULL,
  1014. "Expected 'fi' for if at line %d.",
  1015. Node->LineNumber);
  1016. Result = FALSE;
  1017. goto ParseIfEnd;
  1018. }
  1019. if (SwallowFi != FALSE) {
  1020. Result = ShGetToken(Shell, TRUE);
  1021. if (Result == FALSE) {
  1022. goto ParseIfEnd;
  1023. }
  1024. }
  1025. ParseIfEnd:
  1026. if (Result == FALSE) {
  1027. if (Node != NULL) {
  1028. ShReleaseNode(Node);
  1029. }
  1030. Node = NULL;
  1031. }
  1032. return Node;
  1033. }
  1034. PSHELL_NODE
  1035. ShParseWhileOrUntil (
  1036. PSHELL Shell
  1037. )
  1038. /*++
  1039. Routine Description:
  1040. This routine attempts to parse either a while statement or an until
  1041. statement.
  1042. Arguments:
  1043. Shell - Supplies a pointer to the shell object.
  1044. Return Value:
  1045. Returns a pointer to the node on success.
  1046. NULL on failure.
  1047. --*/
  1048. {
  1049. PSHELL_NODE Condition;
  1050. PSHELL_NODE DoGroup;
  1051. PSHELL_NODE Node;
  1052. SHELL_NODE_TYPE NodeType;
  1053. BOOL Result;
  1054. assert((Shell->Lexer.TokenType == TOKEN_WHILE) ||
  1055. (Shell->Lexer.TokenType == TOKEN_UNTIL));
  1056. if (Shell->Lexer.TokenType == TOKEN_WHILE) {
  1057. NodeType = ShellNodeWhile;
  1058. } else {
  1059. NodeType = ShellNodeUntil;
  1060. }
  1061. Node = ShCreateNode(Shell, NodeType);
  1062. if (Node == NULL) {
  1063. Result = FALSE;
  1064. goto ParseWhileOrUntilEnd;
  1065. }
  1066. //
  1067. // Skip over the while or until.
  1068. //
  1069. Result = ShGetToken(Shell, TRUE);
  1070. if (Result == FALSE) {
  1071. goto ParseWhileOrUntilEnd;
  1072. }
  1073. //
  1074. // Parse the compound list that is the condition.
  1075. //
  1076. Condition = ShParseCompoundList(Shell);
  1077. if (Condition == NULL) {
  1078. Result = FALSE;
  1079. goto ParseWhileOrUntilEnd;
  1080. }
  1081. INSERT_BEFORE(&(Condition->SiblingListEntry), &(Node->Children));
  1082. //
  1083. // Parse the do group of stuff to do inside the loop.
  1084. //
  1085. DoGroup = ShParseDoGroup(Shell);
  1086. if (DoGroup == NULL) {
  1087. Result = FALSE;
  1088. goto ParseWhileOrUntilEnd;
  1089. }
  1090. INSERT_BEFORE(&(DoGroup->SiblingListEntry), &(Node->Children));
  1091. Result = TRUE;
  1092. ParseWhileOrUntilEnd:
  1093. if (Result == FALSE) {
  1094. if (Node != NULL) {
  1095. ShReleaseNode(Node);
  1096. Node = NULL;
  1097. }
  1098. }
  1099. return Node;
  1100. }
  1101. PSHELL_NODE
  1102. ShParseFor (
  1103. PSHELL Shell
  1104. )
  1105. /*++
  1106. Routine Description:
  1107. This routine attempts to parse a for statement.
  1108. Arguments:
  1109. Shell - Supplies a pointer to the shell object.
  1110. Return Value:
  1111. Returns a pointer to the node on success.
  1112. NULL on failure.
  1113. --*/
  1114. {
  1115. PSHELL_NODE DoGroup;
  1116. PSHELL_NODE ForNode;
  1117. BOOL LineBreakRequired;
  1118. BOOL Result;
  1119. assert(Shell->Lexer.TokenType == TOKEN_FOR);
  1120. ForNode = NULL;
  1121. Result = ShGetToken(Shell, FALSE);
  1122. if (Result == FALSE) {
  1123. goto ParseForEnd;
  1124. }
  1125. //
  1126. // The next token is the name of the iterator variable.
  1127. //
  1128. if (Shell->Lexer.TokenType != TOKEN_WORD) {
  1129. ShParseError(Shell, NULL, "Expected 'for' variable iterator name.");
  1130. Result = FALSE;
  1131. goto ParseForEnd;
  1132. }
  1133. Result = ShIsName(Shell->Lexer.TokenBuffer, Shell->Lexer.TokenBufferSize);
  1134. if (Result == FALSE) {
  1135. ShParseError(Shell, NULL, "Bad for loop variable name.");
  1136. goto ParseForEnd;
  1137. }
  1138. ForNode = ShCreateNode(Shell, ShellNodeFor);
  1139. if (ForNode == NULL) {
  1140. Result = FALSE;
  1141. goto ParseForEnd;
  1142. }
  1143. ForNode->U.For.Name = SwStringDuplicate(Shell->Lexer.TokenBuffer,
  1144. Shell->Lexer.TokenBufferSize);
  1145. if (ForNode->U.For.Name == NULL) {
  1146. Result = FALSE;
  1147. goto ParseForEnd;
  1148. }
  1149. ForNode->U.For.NameSize = Shell->Lexer.TokenBufferSize;
  1150. Result = ShGetToken(Shell, FALSE);
  1151. if (Result == FALSE) {
  1152. goto ParseForEnd;
  1153. }
  1154. ShParseLineBreak(Shell, FALSE, FALSE);
  1155. //
  1156. // There can be an "in" next, but it's optional (the command line is used
  1157. // if nothing's supplied).
  1158. //
  1159. LineBreakRequired = FALSE;
  1160. if (Shell->Lexer.TokenType == TOKEN_IN) {
  1161. LineBreakRequired = TRUE;
  1162. Result = ShGetToken(Shell, FALSE);
  1163. if (Result == FALSE) {
  1164. goto ParseForEnd;
  1165. }
  1166. //
  1167. // Now there's an optional wordlist, which means as long as words are
  1168. // coming in add them to the wordlist.
  1169. //
  1170. while (SHELL_TOKEN_WORD_LIKE(Shell->Lexer.TokenType)) {
  1171. Result = ShStringAppend(&(ForNode->U.For.WordListBuffer),
  1172. &(ForNode->U.For.WordListBufferSize),
  1173. &(ForNode->U.For.WordListBufferCapacity),
  1174. Shell->Lexer.TokenBuffer,
  1175. Shell->Lexer.TokenBufferSize);
  1176. if (Result == FALSE) {
  1177. goto ParseForEnd;
  1178. }
  1179. Result = ShGetToken(Shell, FALSE);
  1180. if (Result == FALSE) {
  1181. goto ParseForEnd;
  1182. }
  1183. }
  1184. }
  1185. //
  1186. // Now parse a sequential separator, which is either a semicolon and
  1187. // a linebreak or one or more newlines.
  1188. //
  1189. if (Shell->Lexer.TokenType == ';') {
  1190. Result = ShGetToken(Shell, TRUE);
  1191. if (Result == FALSE) {
  1192. goto ParseForEnd;
  1193. }
  1194. Result = ShParseLineBreak(Shell, FALSE, FALSE);
  1195. } else {
  1196. Result = ShParseLineBreak(Shell, LineBreakRequired, FALSE);
  1197. }
  1198. if (Result == FALSE) {
  1199. goto ParseForEnd;
  1200. }
  1201. //
  1202. // Parse out a "do group" and call it a day.
  1203. //
  1204. DoGroup = ShParseDoGroup(Shell);
  1205. if (DoGroup == NULL) {
  1206. Result = FALSE;
  1207. goto ParseForEnd;
  1208. }
  1209. INSERT_BEFORE(&(DoGroup->SiblingListEntry), &(ForNode->Children));
  1210. Result = TRUE;
  1211. ParseForEnd:
  1212. if (Result == FALSE) {
  1213. if (ForNode != NULL) {
  1214. ShReleaseNode(ForNode);
  1215. ForNode = NULL;
  1216. }
  1217. }
  1218. return ForNode;
  1219. }
  1220. PSHELL_NODE
  1221. ShParseCase (
  1222. PSHELL Shell
  1223. )
  1224. /*++
  1225. Routine Description:
  1226. This routine attempts to parse a case statement.
  1227. Arguments:
  1228. Shell - Supplies a pointer to the shell object.
  1229. Return Value:
  1230. Returns a pointer to the node on success.
  1231. NULL on failure.
  1232. --*/
  1233. {
  1234. PSHELL_NODE CaseNode;
  1235. PSHELL_CASE_PATTERN_SET PatternSet;
  1236. BOOL Result;
  1237. CaseNode = NULL;
  1238. assert(Shell->Lexer.TokenType == TOKEN_CASE);
  1239. Result = ShGetToken(Shell, FALSE);
  1240. if (Result == FALSE) {
  1241. goto ParseCaseEnd;
  1242. }
  1243. //
  1244. // After the word case comes the name of the thing to match against.
  1245. //
  1246. if (!SHELL_TOKEN_WORD_LIKE(Shell->Lexer.TokenType)) {
  1247. ShParseError(Shell, NULL, "Expected case input word.");
  1248. Result = FALSE;
  1249. goto ParseCaseEnd;
  1250. }
  1251. CaseNode = ShCreateNode(Shell, ShellNodeCase);
  1252. if (CaseNode == NULL) {
  1253. Result = FALSE;
  1254. goto ParseCaseEnd;
  1255. }
  1256. CaseNode->U.Case.Name = SwStringDuplicate(Shell->Lexer.TokenBuffer,
  1257. Shell->Lexer.TokenBufferSize);
  1258. if (CaseNode->U.Case.Name == NULL) {
  1259. Result = FALSE;
  1260. goto ParseCaseEnd;
  1261. }
  1262. CaseNode->U.Case.NameSize = Shell->Lexer.TokenBufferSize;
  1263. Result = ShGetToken(Shell, FALSE);
  1264. if (Result == FALSE) {
  1265. goto ParseCaseEnd;
  1266. }
  1267. //
  1268. // Then parse a linebreak.
  1269. //
  1270. Result = ShParseLineBreak(Shell, FALSE, FALSE);
  1271. if (Result == FALSE) {
  1272. goto ParseCaseEnd;
  1273. }
  1274. //
  1275. // Then parse an "in" and another linebreak.
  1276. //
  1277. if (Shell->Lexer.TokenType != TOKEN_IN) {
  1278. ShParseError(Shell, CaseNode, "Expected 'in'.");
  1279. Result = FALSE;
  1280. goto ParseCaseEnd;
  1281. }
  1282. Result = ShGetToken(Shell, FALSE);
  1283. if (Result == FALSE) {
  1284. goto ParseCaseEnd;
  1285. }
  1286. Result = ShParseLineBreak(Shell, FALSE, FALSE);
  1287. if (Result == FALSE) {
  1288. goto ParseCaseEnd;
  1289. }
  1290. //
  1291. // Here comes the case list, which is actually optional altogether.
  1292. //
  1293. while (TRUE) {
  1294. //
  1295. // Parse past an optional opening parentheses.
  1296. //
  1297. if (Shell->Lexer.TokenType == '(') {
  1298. Result = ShGetToken(Shell, FALSE);
  1299. if (Result == FALSE) {
  1300. goto ParseCaseEnd;
  1301. }
  1302. }
  1303. //
  1304. // Scan the pattern(s).
  1305. //
  1306. Result = ShParsePattern(Shell, CaseNode, &PatternSet);
  1307. if (Result == FALSE) {
  1308. goto ParseCaseEnd;
  1309. }
  1310. //
  1311. // If the pattern set is null, this is an esac, stop parsing patterns.
  1312. //
  1313. if (PatternSet == NULL) {
  1314. assert(Shell->Lexer.TokenType == TOKEN_ESAC);
  1315. break;
  1316. }
  1317. //
  1318. // Scan the closing parentheses.
  1319. //
  1320. if (Shell->Lexer.TokenType != ')') {
  1321. ShParseError(Shell, NULL, "Expected ')' to close case pattern.");
  1322. Result = FALSE;
  1323. goto ParseCaseEnd;
  1324. }
  1325. Result = ShGetToken(Shell, TRUE);
  1326. if (Result == FALSE) {
  1327. goto ParseCaseEnd;
  1328. }
  1329. //
  1330. // Scan an optional linebreak.
  1331. //
  1332. Result = ShParseLineBreak(Shell, FALSE, TRUE);
  1333. if (Result == FALSE) {
  1334. goto ParseCaseEnd;
  1335. }
  1336. //
  1337. // Now there's either a compound list there, a double semicolon, or an
  1338. // esac.
  1339. //
  1340. if (Shell->Lexer.TokenType == TOKEN_DOUBLE_SEMICOLON) {
  1341. Result = ShGetToken(Shell, FALSE);
  1342. if (Result == FALSE) {
  1343. goto ParseCaseEnd;
  1344. }
  1345. Result = ShParseLineBreak(Shell, FALSE, TRUE);
  1346. if (Result == FALSE) {
  1347. goto ParseCaseEnd;
  1348. }
  1349. } else if (Shell->Lexer.TokenType == TOKEN_ESAC) {
  1350. break;
  1351. //
  1352. // It must be a compound list.
  1353. //
  1354. } else {
  1355. PatternSet->Action = ShParseCompoundList(Shell);
  1356. if (PatternSet->Action == NULL) {
  1357. goto ParseCaseEnd;
  1358. }
  1359. //
  1360. // Parse an optional linebreak.
  1361. //
  1362. Result = ShParseLineBreak(Shell, FALSE, FALSE);
  1363. if (Result == FALSE) {
  1364. goto ParseCaseEnd;
  1365. }
  1366. //
  1367. // Now there had better be an esac or a double semicolon there.
  1368. //
  1369. if (Shell->Lexer.TokenType == TOKEN_ESAC) {
  1370. break;
  1371. } else if (Shell->Lexer.TokenType != TOKEN_DOUBLE_SEMICOLON) {
  1372. ShParseError(Shell,
  1373. NULL,
  1374. "Expected ';;' for case at line %d.",
  1375. CaseNode->LineNumber);
  1376. Result = FALSE;
  1377. goto ParseCaseEnd;
  1378. }
  1379. //
  1380. // Scan over the double semicolon and an optional linebreak.
  1381. //
  1382. Result = ShGetToken(Shell, FALSE);
  1383. if (Result == FALSE) {
  1384. goto ParseCaseEnd;
  1385. }
  1386. Result = ShParseLineBreak(Shell, FALSE, FALSE);
  1387. if (Result == FALSE) {
  1388. goto ParseCaseEnd;
  1389. }
  1390. }
  1391. }
  1392. //
  1393. // Scan over the esac.
  1394. //
  1395. if (Shell->Lexer.TokenType != TOKEN_ESAC) {
  1396. ShParseError(Shell,
  1397. NULL,
  1398. "Expected 'esac' for case at line %d.",
  1399. CaseNode->LineNumber);
  1400. Result = FALSE;
  1401. goto ParseCaseEnd;
  1402. }
  1403. Result = ShGetToken(Shell, TRUE);
  1404. if (Result == FALSE) {
  1405. goto ParseCaseEnd;
  1406. }
  1407. ParseCaseEnd:
  1408. if (Result == FALSE) {
  1409. if (CaseNode != NULL) {
  1410. ShReleaseNode(CaseNode);
  1411. CaseNode = NULL;
  1412. }
  1413. }
  1414. return CaseNode;
  1415. }
  1416. BOOL
  1417. ShParsePattern (
  1418. PSHELL Shell,
  1419. PSHELL_NODE Case,
  1420. PSHELL_CASE_PATTERN_SET *NewPatternSet
  1421. )
  1422. /*++
  1423. Routine Description:
  1424. This routine attempts to scan a pattern, which is a sequence of 1 or more
  1425. words separated by bars (|).
  1426. Arguments:
  1427. Shell - Supplies a pointer to the shell object.
  1428. Case - Supplies a pointer to the case node where the pattern will be added.
  1429. NewPatternSet - Supplies a pointer where the new pattern set will be
  1430. returned on success.
  1431. Return Value:
  1432. Returns a pointer to the created case pattern on success.
  1433. NULL on failure.
  1434. --*/
  1435. {
  1436. BOOL GotSomething;
  1437. BOOL Result;
  1438. PSHELL_CASE_PATTERN_SET Set;
  1439. assert(Case->Type == ShellNodeCase);
  1440. //
  1441. // Create a pattern set and optimistically add it to the case statement.
  1442. //
  1443. Set = malloc(sizeof(SHELL_CASE_PATTERN_SET));
  1444. if (Set == NULL) {
  1445. return FALSE;
  1446. }
  1447. memset(Set, 0, sizeof(SHELL_CASE_PATTERN_SET));
  1448. INITIALIZE_LIST_HEAD(&(Set->PatternEntryList));
  1449. INSERT_BEFORE(&(Set->ListEntry), &(Case->U.Case.PatternList));
  1450. //
  1451. // Loop through and try to get at least one pattern word out.
  1452. //
  1453. GotSomething = FALSE;
  1454. while (SHELL_TOKEN_WORD_LIKE(Shell->Lexer.TokenType)) {
  1455. //
  1456. // If it's an esac on the first pattern, then treat it with respect.
  1457. //
  1458. if ((Shell->Lexer.TokenType == TOKEN_ESAC) && (GotSomething == FALSE)) {
  1459. break;
  1460. }
  1461. //
  1462. // Add the new pattern word to this set.
  1463. //
  1464. Result = ShAddPatternToSet(Set,
  1465. Shell->Lexer.TokenBuffer,
  1466. Shell->Lexer.TokenBufferSize);
  1467. if (Result == FALSE) {
  1468. goto ParsePatternEnd;
  1469. }
  1470. GotSomething = TRUE;
  1471. Result = ShGetToken(Shell, FALSE);
  1472. if (Result == FALSE) {
  1473. goto ParsePatternEnd;
  1474. }
  1475. //
  1476. // If the next thing isn't a pipe, then this pattern list is over.
  1477. //
  1478. if (Shell->Lexer.TokenType != '|') {
  1479. break;
  1480. }
  1481. Result = ShGetToken(Shell, FALSE);
  1482. if (Result == FALSE) {
  1483. goto ParsePatternEnd;
  1484. }
  1485. }
  1486. //
  1487. // If it was an esac and nothing else, take the set back off the list, this
  1488. // case statement is over.
  1489. //
  1490. if ((GotSomething == FALSE) && (Shell->Lexer.TokenType == TOKEN_ESAC)) {
  1491. assert((Set->Action == NULL) && (LIST_EMPTY(&(Set->PatternEntryList))));
  1492. LIST_REMOVE(&(Set->ListEntry));
  1493. free(Set);
  1494. Set = NULL;
  1495. Result = TRUE;
  1496. } else {
  1497. Result = GotSomething;
  1498. if (Result == FALSE) {
  1499. ShParseError(Shell, Case, "Expected pattern word.");
  1500. }
  1501. }
  1502. ParsePatternEnd:
  1503. *NewPatternSet = Set;
  1504. return Result;
  1505. }
  1506. PSHELL_NODE
  1507. ShParseDoGroup (
  1508. PSHELL Shell
  1509. )
  1510. /*++
  1511. Routine Description:
  1512. This routine attempts to parse a "do group", which consists of "do", a
  1513. compound list, and "done". This is used in most loop constructs.
  1514. Arguments:
  1515. Shell - Supplies a pointer to the shell object.
  1516. Return Value:
  1517. Returns a pointer to the node on success.
  1518. NULL on failure.
  1519. --*/
  1520. {
  1521. PSHELL_NODE CompoundList;
  1522. ULONG DoLineNumber;
  1523. BOOL Result;
  1524. CompoundList = NULL;
  1525. ShParseLineBreak(Shell, FALSE, FALSE);
  1526. //
  1527. // The first thing in a do group should really be a do.
  1528. //
  1529. if (Shell->Lexer.TokenType != TOKEN_DO) {
  1530. ShParseError(Shell, NULL, "Expected 'do'.");
  1531. Result = FALSE;
  1532. goto ParseDoGroupEnd;
  1533. }
  1534. DoLineNumber = Shell->Lexer.LineNumber;
  1535. Result = ShGetToken(Shell, TRUE);
  1536. if (Result == FALSE) {
  1537. goto ParseDoGroupEnd;
  1538. }
  1539. //
  1540. // Now get the compound list.
  1541. //
  1542. CompoundList = ShParseCompoundList(Shell);
  1543. if (CompoundList == NULL) {
  1544. goto ParseDoGroupEnd;
  1545. }
  1546. //
  1547. // Now there should be a done.
  1548. //
  1549. if (Shell->Lexer.TokenType != TOKEN_DONE) {
  1550. ShParseError(Shell,
  1551. NULL,
  1552. "Expected 'done' for 'do' at line %d.",
  1553. DoLineNumber);
  1554. Result = FALSE;
  1555. goto ParseDoGroupEnd;
  1556. }
  1557. Result = ShGetToken(Shell, TRUE);
  1558. if (Result == FALSE) {
  1559. goto ParseDoGroupEnd;
  1560. }
  1561. ParseDoGroupEnd:
  1562. if (Result == FALSE) {
  1563. if (CompoundList != NULL) {
  1564. ShReleaseNode(CompoundList);
  1565. CompoundList = NULL;
  1566. }
  1567. }
  1568. return CompoundList;
  1569. }
  1570. PSHELL_NODE
  1571. ShParseCompoundList (
  1572. PSHELL Shell
  1573. )
  1574. /*++
  1575. Routine Description:
  1576. This routine attempts to parse a compound list.
  1577. Arguments:
  1578. Shell - Supplies a pointer to the shell object.
  1579. Return Value:
  1580. Returns a pointer to the node on success.
  1581. NULL on failure.
  1582. --*/
  1583. {
  1584. PSHELL_NODE CompoundList;
  1585. BOOL Result;
  1586. CHAR Separator;
  1587. CompoundList = NULL;
  1588. //
  1589. // Parse a line break (really just an optional newline list).
  1590. //
  1591. Result = ShParseLineBreak(Shell, FALSE, TRUE);
  1592. if (Result == FALSE) {
  1593. goto ParseCompoundListEnd;
  1594. }
  1595. //
  1596. // Parse a term, call it a compound list.
  1597. //
  1598. CompoundList = ShParseTerm(Shell);
  1599. if (CompoundList == NULL) {
  1600. Result = FALSE;
  1601. goto ParseCompoundListEnd;
  1602. }
  1603. //
  1604. // Parse an optional separator.
  1605. //
  1606. Result = ShParseSeparator(Shell, &Separator);
  1607. if (Result != FALSE) {
  1608. if (Separator == '&') {
  1609. CompoundList->RunInBackground = TRUE;
  1610. }
  1611. }
  1612. Result = TRUE;
  1613. ParseCompoundListEnd:
  1614. if (Result == FALSE) {
  1615. if (CompoundList != NULL) {
  1616. ShReleaseNode(CompoundList);
  1617. CompoundList = NULL;
  1618. }
  1619. }
  1620. return CompoundList;
  1621. }
  1622. PSHELL_NODE
  1623. ShParseTerm (
  1624. PSHELL Shell
  1625. )
  1626. /*++
  1627. Routine Description:
  1628. This routine attempts to parse a term out of the shell input.
  1629. Arguments:
  1630. Shell - Supplies a pointer to the shell object.
  1631. Return Value:
  1632. Returns a pointer to the node on success.
  1633. NULL on failure.
  1634. --*/
  1635. {
  1636. PSHELL_NODE AndOr;
  1637. BOOL Result;
  1638. CHAR SeparatorOp;
  1639. PSHELL_NODE Term;
  1640. Result = FALSE;
  1641. Term = NULL;
  1642. //
  1643. // Parse and-or statements separated by separators (this is different than
  1644. // a list where the separators were separator ops only).
  1645. //
  1646. while (TRUE) {
  1647. AndOr = ShParseAndOr(Shell);
  1648. if (AndOr == NULL) {
  1649. if (Term == NULL) {
  1650. Result = FALSE;
  1651. ShParseError(Shell, NULL, "Unexpected token.");
  1652. goto ParseTermEnd;
  1653. }
  1654. break;
  1655. }
  1656. Result = ShParseSeparator(Shell, &SeparatorOp);
  1657. //
  1658. // If this is the first time around and there's only one item, then
  1659. // just return that item.
  1660. //
  1661. if ((Result == FALSE) && (Term == NULL)) {
  1662. Term = AndOr;
  1663. break;
  1664. }
  1665. //
  1666. // There's more than one and-or. If the list has yet to be made, make it
  1667. // now.
  1668. //
  1669. if (Term == NULL) {
  1670. Term = ShCreateNode(Shell, ShellNodeTerm);
  1671. if (Term == NULL) {
  1672. goto ParseTermEnd;
  1673. }
  1674. }
  1675. INSERT_BEFORE(&(AndOr->SiblingListEntry), &(Term->Children));
  1676. //
  1677. // Regardless of where the command was, if there's no separator, this
  1678. // loop is done.
  1679. //
  1680. if (Result == FALSE) {
  1681. break;
  1682. }
  1683. if (SeparatorOp == '&') {
  1684. AndOr->RunInBackground = TRUE;
  1685. }
  1686. }
  1687. AndOr = NULL;
  1688. Result = TRUE;
  1689. ParseTermEnd:
  1690. if (AndOr != NULL) {
  1691. ShReleaseNode(AndOr);
  1692. }
  1693. if (Result == FALSE) {
  1694. if (Term != NULL) {
  1695. ShReleaseNode(Term);
  1696. Term = NULL;
  1697. }
  1698. }
  1699. return Term;
  1700. }
  1701. PSHELL_NODE
  1702. ShParseSimpleCommandOrFunction (
  1703. PSHELL Shell
  1704. )
  1705. /*++
  1706. Routine Description:
  1707. This routine attempts to parse a simple command or function definition.
  1708. Arguments:
  1709. Shell - Supplies a pointer to the shell object.
  1710. Return Value:
  1711. Returns a pointer to the node on success.
  1712. NULL on failure.
  1713. --*/
  1714. {
  1715. PSHELL_NODE Command;
  1716. PSTR FirstWord;
  1717. UINTN FirstWordSize;
  1718. BOOL Result;
  1719. Command = NULL;
  1720. //
  1721. // Get the first word and look beyond it.
  1722. //
  1723. FirstWord = NULL;
  1724. FirstWordSize = 0;
  1725. if (Shell->Lexer.TokenType == TOKEN_WORD) {
  1726. FirstWordSize = Shell->Lexer.TokenBufferSize;
  1727. FirstWord = SwStringDuplicate(Shell->Lexer.TokenBuffer, FirstWordSize);
  1728. if (FirstWord == NULL) {
  1729. Result = FALSE;
  1730. goto ParseSimpleCommandOrFunctionEnd;
  1731. }
  1732. Result = ShGetToken(Shell, FALSE);
  1733. if (Result == FALSE) {
  1734. goto ParseSimpleCommandOrFunctionEnd;
  1735. }
  1736. }
  1737. //
  1738. // If the next thing is an open parentheses, then it's a function
  1739. // definition. Otherwise it's a simple command.
  1740. //
  1741. if ((ShIsName(FirstWord, FirstWordSize) != FALSE) &&
  1742. (Shell->Lexer.TokenType == '(')) {
  1743. Command = ShParseFunctionDefinition(Shell, FirstWord, FirstWordSize);
  1744. } else {
  1745. Command = ShParseSimpleCommand(Shell, FirstWord, FirstWordSize);
  1746. }
  1747. ParseSimpleCommandOrFunctionEnd:
  1748. if (FirstWord != NULL) {
  1749. free(FirstWord);
  1750. }
  1751. return Command;
  1752. }
  1753. PSHELL_NODE
  1754. ShParseSimpleCommand (
  1755. PSHELL Shell,
  1756. PSTR FirstWord,
  1757. UINTN FirstWordSize
  1758. )
  1759. /*++
  1760. Routine Description:
  1761. This routine attempts to parse a simple command.
  1762. Arguments:
  1763. Shell - Supplies a pointer to the shell object.
  1764. FirstWord - Supplies an optional pointer to the command name that was
  1765. parsed out earlier.
  1766. FirstWordSize - Supplies the size of the first word buffer in bytes
  1767. including the null terminator.
  1768. Return Value:
  1769. Returns a pointer to the node on success.
  1770. NULL on failure.
  1771. --*/
  1772. {
  1773. BOOL AllowAssignmentWords;
  1774. PSHELL_NODE Command;
  1775. BOOL NonEmpty;
  1776. BOOL Result;
  1777. BOOL SwallowToken;
  1778. NonEmpty = FALSE;
  1779. Result = TRUE;
  1780. Command = ShCreateNode(Shell, ShellNodeSimpleCommand);
  1781. if (Command == NULL) {
  1782. return NULL;
  1783. }
  1784. AllowAssignmentWords = TRUE;
  1785. if (FirstWord != NULL) {
  1786. AllowAssignmentWords = FALSE;
  1787. Result = ShAddComponentToCommand(Command, FirstWord, FirstWordSize);
  1788. if (Result == FALSE) {
  1789. goto ParseSimpleCommandEnd;
  1790. }
  1791. NonEmpty = TRUE;
  1792. }
  1793. while (TRUE) {
  1794. SwallowToken = TRUE;
  1795. switch (Shell->Lexer.TokenType) {
  1796. case TOKEN_IO_NUMBER:
  1797. case TOKEN_LESS_THAN_AND:
  1798. case TOKEN_GREATER_THAN_AND:
  1799. case TOKEN_DOUBLE_GREATER_THAN:
  1800. case TOKEN_DOUBLE_LESS_THAN:
  1801. case TOKEN_DOUBLE_LESS_THAN_DASH:
  1802. case TOKEN_LESS_THAN_GREATER_THAN:
  1803. case TOKEN_CLOBBER:
  1804. case '>':
  1805. case '<':
  1806. Result = ShParseRedirection(Shell, Command);
  1807. if (Result == FALSE) {
  1808. goto ParseSimpleCommandEnd;
  1809. }
  1810. SwallowToken = FALSE;
  1811. break;
  1812. case TOKEN_ASSIGNMENT_WORD:
  1813. //
  1814. // If still at that phase (before the initial command word) parse
  1815. // any assignment words that come out. If the assignment word was
  1816. // miscategorized, fall through to the regular word processing.
  1817. //
  1818. if (AllowAssignmentWords != FALSE) {
  1819. Result = ShParseAssignment(Shell, Command);
  1820. if (Result != FALSE) {
  1821. break;
  1822. }
  1823. Result = TRUE;
  1824. }
  1825. //
  1826. // If assignment words are not allowed or the assignment word
  1827. // failed, fall through.
  1828. //
  1829. //
  1830. // Inside of a simple command, they keywords are just regular arguments.
  1831. //
  1832. case TOKEN_IF:
  1833. case TOKEN_THEN:
  1834. case TOKEN_ELSE:
  1835. case TOKEN_ELIF:
  1836. case TOKEN_FI:
  1837. case TOKEN_DO:
  1838. case TOKEN_DONE:
  1839. case TOKEN_CASE:
  1840. case TOKEN_ESAC:
  1841. case TOKEN_WHILE:
  1842. case TOKEN_UNTIL:
  1843. case TOKEN_FOR:
  1844. case TOKEN_IN:
  1845. case TOKEN_WORD:
  1846. case '!':
  1847. case '{':
  1848. case '}':
  1849. Result = ShAddComponentToCommand(Command,
  1850. Shell->Lexer.TokenBuffer,
  1851. Shell->Lexer.TokenBufferSize);
  1852. if (Result == FALSE) {
  1853. goto ParseSimpleCommandEnd;
  1854. }
  1855. AllowAssignmentWords = FALSE;
  1856. break;
  1857. default:
  1858. Result = NonEmpty;
  1859. if (Result == FALSE) {
  1860. ShParseError(Shell, Command, "Expected simple command word.");
  1861. }
  1862. goto ParseSimpleCommandEnd;
  1863. }
  1864. NonEmpty = TRUE;
  1865. if (SwallowToken != FALSE) {
  1866. Result = ShGetToken(Shell, FALSE);
  1867. if (Result == FALSE) {
  1868. goto ParseSimpleCommandEnd;
  1869. }
  1870. }
  1871. }
  1872. ParseSimpleCommandEnd:
  1873. if (Result == FALSE) {
  1874. if (Command != NULL) {
  1875. ShReleaseNode(Command);
  1876. Command = NULL;
  1877. }
  1878. }
  1879. return Command;
  1880. }
  1881. PSHELL_NODE
  1882. ShParseFunctionDefinition (
  1883. PSHELL Shell,
  1884. PSTR FunctionName,
  1885. UINTN FunctionNameSize
  1886. )
  1887. /*++
  1888. Routine Description:
  1889. This routine attempts to parse a function definition.
  1890. Arguments:
  1891. Shell - Supplies a pointer to the shell object.
  1892. FunctionName - Supplies a pointer to the function name.
  1893. FunctionNameSize - Supplies the size of the function name buffer in bytes
  1894. including the null terminator.
  1895. Return Value:
  1896. Returns a pointer to the node on success.
  1897. NULL on failure.
  1898. --*/
  1899. {
  1900. PSHELL_NODE Body;
  1901. PSHELL_NODE Function;
  1902. BOOL Result;
  1903. Result = TRUE;
  1904. Function = ShCreateNode(Shell, ShellNodeFunction);
  1905. if (Function == NULL) {
  1906. return NULL;
  1907. }
  1908. Function->U.Function.Name = SwStringDuplicate(FunctionName,
  1909. FunctionNameSize);
  1910. if (Function->U.Function.Name == NULL) {
  1911. Result = FALSE;
  1912. goto ParseFunctionDefinitionEnd;
  1913. }
  1914. Function->U.Function.NameSize = FunctionNameSize;
  1915. //
  1916. // The current token should be an open parentheses, and then there should
  1917. // be a close parenthese and a newline.
  1918. //
  1919. assert(Shell->Lexer.TokenType == '(');
  1920. Result = ShGetToken(Shell, FALSE);
  1921. if (Result == FALSE) {
  1922. goto ParseFunctionDefinitionEnd;
  1923. }
  1924. if (Shell->Lexer.TokenType != ')') {
  1925. ShParseError(Shell,
  1926. Function,
  1927. "Expected ')' for function definition.");
  1928. Result = FALSE;
  1929. goto ParseFunctionDefinitionEnd;
  1930. }
  1931. Result = ShGetToken(Shell, TRUE);
  1932. if (Result == FALSE) {
  1933. goto ParseFunctionDefinitionEnd;
  1934. }
  1935. Result = ShParseLineBreak(Shell, FALSE, TRUE);
  1936. if (Result == FALSE) {
  1937. goto ParseFunctionDefinitionEnd;
  1938. }
  1939. Body = ShParseCompoundCommand(Shell);
  1940. if (Body == NULL) {
  1941. goto ParseFunctionDefinitionEnd;
  1942. }
  1943. INSERT_BEFORE(&(Body->SiblingListEntry), &(Function->Children));
  1944. //
  1945. // Parse an optional redirect list on the function body.
  1946. //
  1947. Result = ShParseOptionalRedirectList(Shell, Function);
  1948. if (Result == FALSE) {
  1949. goto ParseFunctionDefinitionEnd;
  1950. }
  1951. Result = TRUE;
  1952. ParseFunctionDefinitionEnd:
  1953. if (Result == FALSE) {
  1954. if (Function != NULL) {
  1955. ShReleaseNode(Function);
  1956. Function = NULL;
  1957. }
  1958. }
  1959. return Function;
  1960. }
  1961. BOOL
  1962. ShParseOptionalRedirectList (
  1963. PSHELL Shell,
  1964. PSHELL_NODE Node
  1965. )
  1966. /*++
  1967. Routine Description:
  1968. This routine attempts to parse a redirect list that may or may not be there.
  1969. Arguments:
  1970. Shell - Supplies a pointer to the shell object.
  1971. Node - Supplies a pointer to the node the I/O redirection belongs to.
  1972. Return Value:
  1973. TRUE on success.
  1974. FALSE on failure.
  1975. --*/
  1976. {
  1977. BOOL BreakOut;
  1978. BOOL Result;
  1979. Result = TRUE;
  1980. BreakOut = FALSE;
  1981. while (BreakOut == FALSE) {
  1982. switch (Shell->Lexer.TokenType) {
  1983. case TOKEN_IO_NUMBER:
  1984. case TOKEN_LESS_THAN_AND:
  1985. case TOKEN_GREATER_THAN_AND:
  1986. case TOKEN_DOUBLE_GREATER_THAN:
  1987. case TOKEN_DOUBLE_LESS_THAN:
  1988. case TOKEN_DOUBLE_LESS_THAN_DASH:
  1989. case TOKEN_LESS_THAN_GREATER_THAN:
  1990. case TOKEN_CLOBBER:
  1991. case '>':
  1992. case '<':
  1993. Result = ShParseRedirection(Shell, Node);
  1994. if (Result == FALSE) {
  1995. goto ParseOptionalRedirectListEnd;
  1996. }
  1997. break;
  1998. default:
  1999. BreakOut = TRUE;
  2000. break;
  2001. }
  2002. }
  2003. ParseOptionalRedirectListEnd:
  2004. return Result;
  2005. }
  2006. BOOL
  2007. ShParseRedirection (
  2008. PSHELL Shell,
  2009. PSHELL_NODE Node
  2010. )
  2011. /*++
  2012. Routine Description:
  2013. This routine attempts to parse an I/O redirection.
  2014. Arguments:
  2015. Shell - Supplies a pointer to the shell object.
  2016. Node - Supplies a pointer to the node the I/O redirection belongs to.
  2017. Return Value:
  2018. TRUE on success.
  2019. FALSE on failure.
  2020. --*/
  2021. {
  2022. ULONG DefaultFileNumber;
  2023. PSTR FileName;
  2024. UINTN FileNameSize;
  2025. ULONG FileNumber;
  2026. BOOL Result;
  2027. SHELL_IO_REDIRECTION_TYPE Type;
  2028. DefaultFileNumber = -1;
  2029. FileNumber = -1;
  2030. Type = ShellRedirectInvalid;
  2031. //
  2032. // Start by attempting to get an I/O number.
  2033. //
  2034. if (Shell->Lexer.TokenType == TOKEN_IO_NUMBER) {
  2035. FileNumber = strtol(Shell->Lexer.TokenBuffer, NULL, 10);
  2036. if (FileNumber < 0) {
  2037. //
  2038. // The lexer should have stripped off any piece that couldn't be
  2039. // interpreted as a positive number, so it's weird that this
  2040. // number wouldn't convert.
  2041. //
  2042. assert(FALSE);
  2043. Result = FALSE;
  2044. goto ParseRedirectionEnd;
  2045. }
  2046. Result = ShGetToken(Shell, FALSE);
  2047. if (Result == FALSE) {
  2048. goto ParseRedirectionEnd;
  2049. }
  2050. }
  2051. //
  2052. // Now get the operator.
  2053. //
  2054. switch (Shell->Lexer.TokenType) {
  2055. case TOKEN_LESS_THAN_AND:
  2056. Type = ShellRedirectReadFromDescriptor;
  2057. DefaultFileNumber = STDIN_FILENO;
  2058. break;
  2059. case TOKEN_GREATER_THAN_AND:
  2060. Type = ShellRedirectWriteToDescriptor;
  2061. DefaultFileNumber = STDOUT_FILENO;
  2062. break;
  2063. case TOKEN_DOUBLE_GREATER_THAN:
  2064. Type = ShellRedirectAppend;
  2065. DefaultFileNumber = STDOUT_FILENO;
  2066. break;
  2067. case TOKEN_DOUBLE_LESS_THAN:
  2068. Type = ShellRedirectHereDocument;
  2069. DefaultFileNumber = STDIN_FILENO;
  2070. break;
  2071. case TOKEN_DOUBLE_LESS_THAN_DASH:
  2072. Type = ShellRedirectStrippedHereDocument;
  2073. DefaultFileNumber = STDIN_FILENO;
  2074. break;
  2075. case TOKEN_LESS_THAN_GREATER_THAN:
  2076. Type = ShellRedirectReadWrite;
  2077. DefaultFileNumber = STDIN_FILENO;
  2078. break;
  2079. case TOKEN_CLOBBER:
  2080. Type = ShellRedirectClobber;
  2081. DefaultFileNumber = STDOUT_FILENO;
  2082. break;
  2083. case '>':
  2084. Type = ShellRedirectWrite;
  2085. DefaultFileNumber = STDOUT_FILENO;
  2086. break;
  2087. case '<':
  2088. Type = ShellRedirectRead;
  2089. DefaultFileNumber = STDIN_FILENO;
  2090. break;
  2091. default:
  2092. Result = FALSE;
  2093. goto ParseRedirectionEnd;
  2094. }
  2095. Result = ShGetToken(Shell, FALSE);
  2096. if (Result == FALSE) {
  2097. goto ParseRedirectionEnd;
  2098. }
  2099. //
  2100. // Now get the word of where to redirect to. Convert to a file descriptor
  2101. // number if needed.
  2102. //
  2103. if (!SHELL_TOKEN_WORD_LIKE(Shell->Lexer.TokenType)) {
  2104. ShParseError(Shell, Node, "Expected redirection file name.");
  2105. Result = FALSE;
  2106. goto ParseRedirectionEnd;
  2107. }
  2108. FileName = Shell->Lexer.TokenBuffer;
  2109. FileNameSize = Shell->Lexer.TokenBufferSize;
  2110. if (FileNumber == -1) {
  2111. FileNumber = DefaultFileNumber;
  2112. }
  2113. Result = ShCreateRedirection(Shell,
  2114. Node,
  2115. Type,
  2116. FileNumber,
  2117. FileName,
  2118. FileNameSize);
  2119. if (Result == FALSE) {
  2120. goto ParseRedirectionEnd;
  2121. }
  2122. Result = ShGetToken(Shell, TRUE);
  2123. if (Result == FALSE) {
  2124. goto ParseRedirectionEnd;
  2125. }
  2126. ParseRedirectionEnd:
  2127. return Result;
  2128. }
  2129. BOOL
  2130. ShParseAssignment (
  2131. PSHELL Shell,
  2132. PSHELL_NODE Node
  2133. )
  2134. /*++
  2135. Routine Description:
  2136. This routine attempts to parse an assignment word.
  2137. Arguments:
  2138. Shell - Supplies a pointer to the shell object.
  2139. Node - Supplies a pointer to the node the assignment belongs to.
  2140. Return Value:
  2141. TRUE on success.
  2142. FALSE on failure.
  2143. --*/
  2144. {
  2145. PSTR Name;
  2146. UINTN NameSize;
  2147. BOOL Result;
  2148. PSTR Token;
  2149. UINTN TokenSize;
  2150. PSTR Value;
  2151. UINTN ValueSize;
  2152. Token = Shell->Lexer.TokenBuffer;
  2153. TokenSize = Shell->Lexer.TokenBufferSize;
  2154. Name = Token;
  2155. Value = strchr(Token, '=');
  2156. if (Value == NULL) {
  2157. //
  2158. // How would something get here unless this was already categorized as
  2159. // an assignment word?
  2160. //
  2161. assert(FALSE);
  2162. return FALSE;
  2163. }
  2164. //
  2165. // There can't be a zero length name.
  2166. //
  2167. if (Value == Token) {
  2168. return FALSE;
  2169. }
  2170. NameSize = ((UINTN)Value - (UINTN)Token);
  2171. if (ShIsName(Name, NameSize) == FALSE) {
  2172. return FALSE;
  2173. }
  2174. NameSize += 1;
  2175. Value += 1;
  2176. ValueSize = TokenSize - ((UINTN)Value - (UINTN)Token);
  2177. Result = ShCreateAssignment(Node, Name, NameSize, Value, ValueSize);
  2178. return Result;
  2179. }
  2180. BOOL
  2181. ShParseLineBreak (
  2182. PSHELL Shell,
  2183. BOOL Required,
  2184. BOOL FirstCommandWord
  2185. )
  2186. /*++
  2187. Routine Description:
  2188. This routine parses a line break term, which is just zero or more newline.
  2189. Arguments:
  2190. Shell - Supplies a pointer to the shell whose input is being parsed.
  2191. Required - Supplies a boolean indicating if at least one line break is
  2192. required.
  2193. FirstCommandWord - Supplies the boolean that will be passed to the get
  2194. token routine indicating whether or not this next token could be the
  2195. command word of a simple command.
  2196. Return Value:
  2197. TRUE on success.
  2198. FALSE if the lexer failed to get a token.
  2199. --*/
  2200. {
  2201. BOOL Result;
  2202. if ((Required != FALSE) && (Shell->Lexer.TokenType != '\n')) {
  2203. return FALSE;
  2204. }
  2205. while (Shell->Lexer.TokenType == '\n') {
  2206. ShPrintPrompt(Shell, 2);
  2207. Result = ShGetToken(Shell, FirstCommandWord);
  2208. if (Result == FALSE) {
  2209. return FALSE;
  2210. }
  2211. }
  2212. return TRUE;
  2213. }
  2214. BOOL
  2215. ShParseSeparator (
  2216. PSHELL Shell,
  2217. PCHAR Separator
  2218. )
  2219. /*++
  2220. Routine Description:
  2221. This routine attempts to parse a separator, which is either a separator op
  2222. followed by a linebreak, or 1+ newlines.
  2223. Arguments:
  2224. Shell - Supplies a pointer to the shell whose input is being parsed.
  2225. Separator - Supplies a pointer where the separator character will be
  2226. returned on success, or 0 if there was no separator.
  2227. Return Value:
  2228. TRUE if a separator operator was parsed.
  2229. FALSE if there was no separator or the lexer failed to move on.
  2230. --*/
  2231. {
  2232. BOOL Result;
  2233. //
  2234. // First try to get a separator op and linebreak. A linebreak swallows a
  2235. // newline list.
  2236. //
  2237. Result = ShParseSeparatorOp(Shell, Separator);
  2238. if (Result != FALSE) {
  2239. Result = ShParseLineBreak(Shell, FALSE, TRUE);
  2240. //
  2241. // There's no separator op, try to get at least one newline.
  2242. //
  2243. } else {
  2244. Result = ShParseLineBreak(Shell, TRUE, TRUE);
  2245. }
  2246. return Result;
  2247. }
  2248. BOOL
  2249. ShParseSeparatorOp (
  2250. PSHELL Shell,
  2251. PCHAR Separator
  2252. )
  2253. /*++
  2254. Routine Description:
  2255. This routine attempts to parse a separator operator, which is either a
  2256. semicolon or an ampersand.
  2257. Arguments:
  2258. Shell - Supplies a pointer to the shell whose input is being parsed.
  2259. Separator - Supplies a pointer where the separator character will be
  2260. returned on success, or 0 if there was no separator.
  2261. Return Value:
  2262. TRUE if a separator operator was parsed.
  2263. FALSE if there was no separator or the lexer failed to move on.
  2264. --*/
  2265. {
  2266. BOOL Result;
  2267. if ((Shell->Lexer.TokenType == ';') || (Shell->Lexer.TokenType == '&')) {
  2268. *Separator = Shell->Lexer.TokenType;
  2269. Result = ShGetToken(Shell, TRUE);
  2270. return Result;
  2271. }
  2272. return FALSE;
  2273. }
  2274. PSHELL_NODE
  2275. ShCreateNode (
  2276. PSHELL Shell,
  2277. SHELL_NODE_TYPE Type
  2278. )
  2279. /*++
  2280. Routine Description:
  2281. This routine allocates and initializes a shell node.
  2282. Arguments:
  2283. Shell - Supplies a pointer to the shell.
  2284. Type - Supplies the type of node to create.
  2285. Return Value:
  2286. Returns a pointer to the node on success.
  2287. NULL on failure.
  2288. --*/
  2289. {
  2290. PSHELL_NODE NewNode;
  2291. NewNode = malloc(sizeof(SHELL_NODE));
  2292. if (NewNode == NULL) {
  2293. return NULL;
  2294. }
  2295. NewNode->Type = Type;
  2296. NewNode->ReferenceCount = 1;
  2297. NewNode->LineNumber = Shell->Lexer.LineNumber;
  2298. if (Shell->Lexer.TokenType == '\n') {
  2299. NewNode->LineNumber -= 1;
  2300. }
  2301. INITIALIZE_LIST_HEAD(&(NewNode->Children));
  2302. INITIALIZE_LIST_HEAD(&(NewNode->RedirectList));
  2303. NewNode->RunInBackground = FALSE;
  2304. NewNode->AndOr = 0;
  2305. switch (Type) {
  2306. case ShellNodePipeline:
  2307. NewNode->U.Pipeline.Bang = FALSE;
  2308. break;
  2309. case ShellNodeSimpleCommand:
  2310. memset(&(NewNode->U.SimpleCommand),
  2311. 0,
  2312. sizeof(SHELL_NODE_SIMPLE_COMMAND));
  2313. INITIALIZE_LIST_HEAD(&(NewNode->U.SimpleCommand.AssignmentList));
  2314. break;
  2315. case ShellNodeFunction:
  2316. memset(&(NewNode->U.Function), 0, sizeof(SHELL_NODE_FUNCTION));
  2317. break;
  2318. case ShellNodeFor:
  2319. memset(&(NewNode->U.For), 0, sizeof(SHELL_NODE_FOR));
  2320. break;
  2321. case ShellNodeCase:
  2322. memset(&(NewNode->U.Case), 0, sizeof(SHELL_NODE_CASE));
  2323. INITIALIZE_LIST_HEAD(&(NewNode->U.Case.PatternList));
  2324. break;
  2325. default:
  2326. break;
  2327. }
  2328. return NewNode;
  2329. }
  2330. VOID
  2331. ShDeleteNode (
  2332. PSHELL_NODE Node
  2333. )
  2334. /*++
  2335. Routine Description:
  2336. This routine destroys a shell node.
  2337. Arguments:
  2338. Node - Supplies a pointer to the node to destroy.
  2339. Return Value:
  2340. None.
  2341. --*/
  2342. {
  2343. PSHELL_ASSIGNMENT Assignment;
  2344. PSHELL_NODE Child;
  2345. PSHELL_IO_REDIRECT Redirect;
  2346. assert(Node->ReferenceCount == 0);
  2347. switch (Node->Type) {
  2348. case ShellNodeSimpleCommand:
  2349. while (LIST_EMPTY(&(Node->U.SimpleCommand.AssignmentList)) == FALSE) {
  2350. Assignment = LIST_VALUE(Node->U.SimpleCommand.AssignmentList.Next,
  2351. SHELL_ASSIGNMENT,
  2352. ListEntry);
  2353. ShDestroyAssignment(Assignment);
  2354. }
  2355. if (Node->U.SimpleCommand.Arguments != NULL) {
  2356. free(Node->U.SimpleCommand.Arguments);
  2357. }
  2358. break;
  2359. case ShellNodeFunction:
  2360. if (Node->U.Function.Name != NULL) {
  2361. free(Node->U.Function.Name);
  2362. }
  2363. break;
  2364. case ShellNodeFor:
  2365. if (Node->U.For.Name != NULL) {
  2366. free(Node->U.For.Name);
  2367. }
  2368. if (Node->U.For.WordListBuffer != NULL) {
  2369. free(Node->U.For.WordListBuffer);
  2370. }
  2371. break;
  2372. case ShellNodeCase:
  2373. ShDestroyCasePatternList(Node);
  2374. if (Node->U.Case.Name != NULL) {
  2375. free(Node->U.Case.Name);
  2376. }
  2377. break;
  2378. default:
  2379. break;
  2380. }
  2381. while (LIST_EMPTY(&(Node->RedirectList)) == FALSE) {
  2382. Redirect = LIST_VALUE(Node->RedirectList.Next,
  2383. SHELL_IO_REDIRECT,
  2384. ListEntry);
  2385. ShDestroyRedirection(Redirect);
  2386. }
  2387. while (LIST_EMPTY(&(Node->Children)) == FALSE) {
  2388. Child = LIST_VALUE(Node->Children.Next, SHELL_NODE, SiblingListEntry);
  2389. LIST_REMOVE(&(Child->SiblingListEntry));
  2390. ShReleaseNode(Child);
  2391. }
  2392. free(Node);
  2393. return;
  2394. }
  2395. VOID
  2396. ShPrintNode (
  2397. PSHELL Shell,
  2398. PSHELL_NODE Node,
  2399. ULONG Depth
  2400. )
  2401. /*++
  2402. Routine Description:
  2403. This routine prints out a parsed shell node.
  2404. Arguments:
  2405. Shell - Supplies a pointer to the shell.
  2406. Node - Supplies a pointer to the node to print.
  2407. Depth - Supplies the indentation depth to print it at.
  2408. Return Value:
  2409. None.
  2410. --*/
  2411. {
  2412. PSHELL_ASSIGNMENT Assignment;
  2413. PSHELL_NODE Child;
  2414. PLIST_ENTRY CurrentEntry;
  2415. PLIST_ENTRY CurrentEntryEntry;
  2416. ULONG DepthIndex;
  2417. PSHELL_CASE_PATTERN_ENTRY Entry;
  2418. PSHELL_IO_REDIRECT Redirect;
  2419. PSHELL_CASE_PATTERN_SET Set;
  2420. for (DepthIndex = 0; DepthIndex < Depth; DepthIndex += 1) {
  2421. ShPrintTrace(Shell, " ");
  2422. }
  2423. ShPrintTrace(Shell, "Line %d ", Node->LineNumber);
  2424. switch (Node->Type) {
  2425. case ShellNodeInvalid:
  2426. ShPrintTrace(Shell, "Invalid Node");
  2427. break;
  2428. case ShellNodeList:
  2429. ShPrintTrace(Shell, "List");
  2430. break;
  2431. case ShellNodeAndOr:
  2432. ShPrintTrace(Shell, "AndOr");
  2433. break;
  2434. case ShellNodePipeline:
  2435. if (Node->U.Pipeline.Bang != FALSE) {
  2436. ShPrintTrace(Shell, "! ");
  2437. }
  2438. ShPrintTrace(Shell, "Pipeline");
  2439. break;
  2440. case ShellNodeSimpleCommand:
  2441. ShPrintTrace(Shell, "SimpleCommand:");
  2442. CurrentEntry = Node->U.SimpleCommand.AssignmentList.Next;
  2443. while (CurrentEntry != &(Node->U.SimpleCommand.AssignmentList)) {
  2444. Assignment = LIST_VALUE(CurrentEntry, SHELL_ASSIGNMENT, ListEntry);
  2445. CurrentEntry = CurrentEntry->Next;
  2446. ShPrintTrace(Shell,
  2447. " [%s]=[%s]",
  2448. Assignment->Name,
  2449. Assignment->Value);
  2450. }
  2451. ShPrintTrace(Shell, " [%s] ", Node->U.SimpleCommand.Arguments);
  2452. break;
  2453. case ShellNodeFunction:
  2454. ShPrintTrace(Shell, "Function %s", Node->U.Function.Name);
  2455. break;
  2456. case ShellNodeIf:
  2457. ShPrintTrace(Shell, "If");
  2458. break;
  2459. case ShellNodeTerm:
  2460. ShPrintTrace(Shell, "Term");
  2461. break;
  2462. case ShellNodeFor:
  2463. ShPrintTrace(Shell,
  2464. "For [%s] in [%s]",
  2465. Node->U.For.Name,
  2466. Node->U.For.WordListBuffer);
  2467. ShPrintTrace(Shell, " do");
  2468. break;
  2469. case ShellNodeBraceGroup:
  2470. ShPrintTrace(Shell, "BraceGroup");
  2471. break;
  2472. case ShellNodeCase:
  2473. ShPrintTrace(Shell, "Case [%s]", Node->U.Case.Name);
  2474. break;
  2475. case ShellNodeWhile:
  2476. ShPrintTrace(Shell, "While");
  2477. break;
  2478. case ShellNodeUntil:
  2479. ShPrintTrace(Shell, "Until");
  2480. break;
  2481. case ShellNodeSubshell:
  2482. ShPrintTrace(Shell, "Subshell");
  2483. break;
  2484. default:
  2485. assert(FALSE);
  2486. break;
  2487. }
  2488. CurrentEntry = Node->RedirectList.Next;
  2489. while (CurrentEntry != &(Node->RedirectList)) {
  2490. Redirect = LIST_VALUE(CurrentEntry, SHELL_IO_REDIRECT, ListEntry);
  2491. CurrentEntry = CurrentEntry->Next;
  2492. switch (Redirect->Type) {
  2493. case ShellRedirectInvalid:
  2494. ShPrintTrace(Shell, " INVALID_REDIRECT");
  2495. break;
  2496. case ShellRedirectRead:
  2497. ShPrintTrace(Shell,
  2498. " [%d<%s]",
  2499. Redirect->FileNumber,
  2500. Redirect->FileName);
  2501. break;
  2502. case ShellRedirectReadFromDescriptor:
  2503. ShPrintTrace(Shell,
  2504. " [%d<&%s]",
  2505. Redirect->FileNumber,
  2506. Redirect->FileName);
  2507. break;
  2508. case ShellRedirectWrite:
  2509. ShPrintTrace(Shell,
  2510. " [%d>%s]",
  2511. Redirect->FileNumber,
  2512. Redirect->FileName);
  2513. break;
  2514. case ShellRedirectWriteToDescriptor:
  2515. ShPrintTrace(Shell,
  2516. " [%d>&%s]",
  2517. Redirect->FileNumber,
  2518. Redirect->FileName);
  2519. break;
  2520. case ShellRedirectClobber:
  2521. ShPrintTrace(Shell,
  2522. " [%d>|%s]",
  2523. Redirect->FileNumber,
  2524. Redirect->FileName);
  2525. break;
  2526. case ShellRedirectAppend:
  2527. ShPrintTrace(Shell,
  2528. " [%d>>%s]",
  2529. Redirect->FileNumber,
  2530. Redirect->FileName);
  2531. break;
  2532. case ShellRedirectReadWrite:
  2533. ShPrintTrace(Shell,
  2534. " [%d<>%s]",
  2535. Redirect->FileNumber,
  2536. Redirect->FileName);
  2537. break;
  2538. case ShellRedirectHereDocument:
  2539. ShPrintTrace(Shell,
  2540. " [%d<<]>>>>\n",
  2541. Redirect->FileNumber);
  2542. ShPrintTrace(Shell,
  2543. "%s\n<<<<",
  2544. Redirect->HereDocument->Document);
  2545. break;
  2546. case ShellRedirectStrippedHereDocument:
  2547. ShPrintTrace(Shell, " [%d<<-]>>>>\n", Redirect->FileNumber);
  2548. ShPrintTrace(Shell, "%s\n<<<<", Redirect->HereDocument->Document);
  2549. break;
  2550. default:
  2551. assert(FALSE);
  2552. break;
  2553. }
  2554. }
  2555. if (Node->RunInBackground != FALSE) {
  2556. ShPrintTrace(Shell, " &");
  2557. }
  2558. if (Node->AndOr == TOKEN_DOUBLE_AND) {
  2559. ShPrintTrace(Shell, " &&");
  2560. } else if (Node->AndOr == TOKEN_DOUBLE_OR) {
  2561. ShPrintTrace(Shell, " ||");
  2562. }
  2563. ShPrintTrace(Shell, "\n");
  2564. if (Node->Type == ShellNodeCase) {
  2565. //
  2566. // Loop through every set in the case.
  2567. //
  2568. CurrentEntry = Node->U.Case.PatternList.Next;
  2569. while (CurrentEntry != &(Node->U.Case.PatternList)) {
  2570. Set = LIST_VALUE(CurrentEntry, SHELL_CASE_PATTERN_SET, ListEntry);
  2571. CurrentEntry = CurrentEntry->Next;
  2572. //
  2573. // Loop through every entry in the set.
  2574. //
  2575. CurrentEntryEntry = Set->PatternEntryList.Next;
  2576. while (CurrentEntryEntry != &(Set->PatternEntryList)) {
  2577. Entry = LIST_VALUE(CurrentEntryEntry,
  2578. SHELL_CASE_PATTERN_ENTRY,
  2579. ListEntry);
  2580. CurrentEntryEntry = CurrentEntryEntry->Next;
  2581. for (DepthIndex = 0; DepthIndex < Depth + 1; DepthIndex += 1) {
  2582. ShPrintTrace(Shell, " ");
  2583. }
  2584. ShPrintTrace(Shell, "Pattern: %s\n", Entry->Pattern);
  2585. }
  2586. if (Set->Action != NULL) {
  2587. ShPrintNode(Shell, Set->Action, Depth + 2);
  2588. } else {
  2589. for (DepthIndex = 0; DepthIndex < Depth + 2; DepthIndex += 1) {
  2590. ShPrintTrace(Shell, " ");
  2591. }
  2592. ShPrintTrace(Shell, "No Action");
  2593. }
  2594. }
  2595. }
  2596. CurrentEntry = Node->Children.Next;
  2597. while (CurrentEntry != &(Node->Children)) {
  2598. Child = LIST_VALUE(CurrentEntry, SHELL_NODE, SiblingListEntry);
  2599. CurrentEntry = CurrentEntry->Next;
  2600. ShPrintNode(Shell, Child, Depth + 1);
  2601. }
  2602. return;
  2603. }
  2604. BOOL
  2605. ShCreateRedirection (
  2606. PSHELL Shell,
  2607. PSHELL_NODE Node,
  2608. SHELL_IO_REDIRECTION_TYPE Type,
  2609. INT FileNumber,
  2610. PSTR FileName,
  2611. UINTN FileNameSize
  2612. )
  2613. /*++
  2614. Routine Description:
  2615. This routine creates a new I/O redirection entry and puts it on the list
  2616. for the given node.
  2617. Arguments:
  2618. Shell - Supplies a pointer to the shell the redirection is executing on.
  2619. Node - Supplies a pointer to the shell node (probably a command).
  2620. Type - Supplies the type of redirection.
  2621. FileNumber - Supplies the file number being affected by the redirection.
  2622. FileName - Supplies the optional name of the file being redirected to or
  2623. from. If this parameter is not NULL, a copy of the given string will
  2624. be made.
  2625. FileNameSize - Supplies the size of the file name buffer in bytes.
  2626. Return Value:
  2627. TRUE on success.
  2628. FALSE on failure.
  2629. --*/
  2630. {
  2631. PSHELL_HERE_DOCUMENT HereDocument;
  2632. PSHELL_IO_REDIRECT Redirect;
  2633. BOOL Result;
  2634. HereDocument = NULL;
  2635. Redirect = malloc(sizeof(SHELL_IO_REDIRECT));
  2636. if (Redirect == NULL) {
  2637. return FALSE;
  2638. }
  2639. memset(Redirect, 0, sizeof(SHELL_IO_REDIRECT));
  2640. Redirect->Type = Type;
  2641. Redirect->FileNumber = FileNumber;
  2642. //
  2643. // If it's a here document, create a new structure and add it to the
  2644. // lexer's list of pending here documents.
  2645. //
  2646. if ((Redirect->Type == ShellRedirectHereDocument) ||
  2647. (Redirect->Type == ShellRedirectStrippedHereDocument)) {
  2648. HereDocument = malloc(sizeof(SHELL_HERE_DOCUMENT));
  2649. if (HereDocument == NULL) {
  2650. Result = FALSE;
  2651. goto CreateRedirectionEnd;
  2652. }
  2653. memset(HereDocument, 0, sizeof(SHELL_HERE_DOCUMENT));
  2654. if (Redirect->Type == ShellRedirectStrippedHereDocument) {
  2655. HereDocument->StripLeadingTabs = TRUE;
  2656. }
  2657. if (ShIsStringQuoted(FileName) != FALSE) {
  2658. HereDocument->EndWordWasQuoted = TRUE;
  2659. }
  2660. HereDocument->EndWord = SwStringDuplicate(FileName, FileNameSize);
  2661. if (HereDocument->EndWord == NULL) {
  2662. Result = FALSE;
  2663. goto CreateRedirectionEnd;
  2664. }
  2665. HereDocument->EndWordSize = FileNameSize;
  2666. ShStringDequote(HereDocument->EndWord,
  2667. HereDocument->EndWordSize,
  2668. 0,
  2669. &(HereDocument->EndWordSize));
  2670. INSERT_BEFORE(&(HereDocument->ListEntry),
  2671. &(Shell->Lexer.HereDocumentList));
  2672. Redirect->HereDocument = HereDocument;
  2673. } else if (FileName != NULL) {
  2674. Redirect->FileNameSize = FileNameSize;
  2675. Redirect->FileName = SwStringDuplicate(FileName, FileNameSize);
  2676. if (Redirect->FileName == NULL) {
  2677. Result = FALSE;
  2678. goto CreateRedirectionEnd;
  2679. }
  2680. }
  2681. INSERT_BEFORE(&(Redirect->ListEntry), &(Node->RedirectList));
  2682. Result = TRUE;
  2683. CreateRedirectionEnd:
  2684. if (Result == FALSE) {
  2685. if (HereDocument != NULL) {
  2686. ShDestroyHereDocument(HereDocument);
  2687. }
  2688. if (Redirect != NULL) {
  2689. ShDestroyRedirection(Redirect);
  2690. }
  2691. }
  2692. return Result;
  2693. }
  2694. VOID
  2695. ShDestroyRedirection (
  2696. PSHELL_IO_REDIRECT Redirect
  2697. )
  2698. /*++
  2699. Routine Description:
  2700. This routine destroys an I/O redirection entry.
  2701. Arguments:
  2702. Redirect - Supplies a pointer to the redirect entry.
  2703. Return Value:
  2704. None.
  2705. --*/
  2706. {
  2707. LIST_REMOVE(&(Redirect->ListEntry));
  2708. if (Redirect->FileName != NULL) {
  2709. free(Redirect->FileName);
  2710. }
  2711. if (Redirect->HereDocument != NULL) {
  2712. if (Redirect->HereDocument->ListEntry.Next != NULL) {
  2713. LIST_REMOVE(&(Redirect->HereDocument->ListEntry));
  2714. }
  2715. ShDestroyHereDocument(Redirect->HereDocument);
  2716. }
  2717. free(Redirect);
  2718. return;
  2719. }
  2720. BOOL
  2721. ShCreateAssignment (
  2722. PSHELL_NODE Node,
  2723. PSTR Name,
  2724. UINTN NameSize,
  2725. PSTR Value,
  2726. UINTN ValueSize
  2727. )
  2728. /*++
  2729. Routine Description:
  2730. This routine creates an assignment structure.
  2731. Arguments:
  2732. Node - Supplies a pointer to the node to put the assignment on.
  2733. Name - Supplies a pointer to the name string. A copy of this string will be
  2734. made.
  2735. NameSize - Supplies the length of the name string including a null
  2736. terminator.
  2737. Value - Supplies a pointer to the value string. A copy of this string will
  2738. be made.
  2739. ValueSize - Supplies the length of the value string including a null
  2740. terminator.
  2741. Return Value:
  2742. TRUE on success.
  2743. FALSE on allocation failure.
  2744. --*/
  2745. {
  2746. PSHELL_ASSIGNMENT Assignment;
  2747. BOOL Result;
  2748. Result = FALSE;
  2749. Assignment = malloc(sizeof(SHELL_ASSIGNMENT));
  2750. if (Assignment == NULL) {
  2751. return FALSE;
  2752. }
  2753. memset(Assignment, 0, sizeof(SHELL_ASSIGNMENT));
  2754. Assignment->Name = SwStringDuplicate(Name, NameSize);
  2755. if (Assignment->Name == NULL) {
  2756. goto CreateAssignmentEnd;
  2757. }
  2758. Assignment->NameSize = NameSize;
  2759. Assignment->Value = SwStringDuplicate(Value, ValueSize);
  2760. if (Assignment->Value == NULL) {
  2761. goto CreateAssignmentEnd;
  2762. }
  2763. Assignment->ValueSize = ValueSize;
  2764. assert(Node->Type == ShellNodeSimpleCommand);
  2765. INSERT_BEFORE(&(Assignment->ListEntry),
  2766. &(Node->U.SimpleCommand.AssignmentList));
  2767. Result = TRUE;
  2768. CreateAssignmentEnd:
  2769. if (Result == FALSE) {
  2770. if (Assignment != NULL) {
  2771. if (Assignment->Name != NULL) {
  2772. free(Assignment->Name);
  2773. }
  2774. if (Assignment->Value != NULL) {
  2775. free(Assignment->Value);
  2776. }
  2777. free(Assignment);
  2778. }
  2779. }
  2780. return Result;
  2781. }
  2782. VOID
  2783. ShDestroyAssignment (
  2784. PSHELL_ASSIGNMENT Assignment
  2785. )
  2786. /*++
  2787. Routine Description:
  2788. This routine destroys an assignment entry.
  2789. Arguments:
  2790. Assignment - Supplies a pointer to the assignment.
  2791. Return Value:
  2792. None.
  2793. --*/
  2794. {
  2795. LIST_REMOVE(&(Assignment->ListEntry));
  2796. if (Assignment->Name != NULL) {
  2797. free(Assignment->Name);
  2798. }
  2799. if (Assignment->Value != NULL) {
  2800. free(Assignment->Value);
  2801. }
  2802. free(Assignment);
  2803. return;
  2804. }
  2805. BOOL
  2806. ShAddPatternToSet (
  2807. PSHELL_CASE_PATTERN_SET Set,
  2808. PSTR Pattern,
  2809. UINTN PatternSize
  2810. )
  2811. /*++
  2812. Routine Description:
  2813. This routine adds a case pattern entry to the given case statement.
  2814. Arguments:
  2815. Set - Supplies a pointer to the set of patterns.
  2816. Pattern - Supplies a pointer to the pattern string to add. A copy of this
  2817. string will be made.
  2818. PatternSize - Supplies the length of the pattern string in bytes including
  2819. the null terminator.
  2820. Return Value:
  2821. TRUE on success.
  2822. FALSE on failure.
  2823. --*/
  2824. {
  2825. PSHELL_CASE_PATTERN_ENTRY Entry;
  2826. Entry = malloc(sizeof(SHELL_CASE_PATTERN_ENTRY));
  2827. if (Entry == NULL) {
  2828. return FALSE;
  2829. }
  2830. Entry->Pattern = SwStringDuplicate(Pattern, PatternSize);
  2831. if (Entry->Pattern == NULL) {
  2832. free(Entry);
  2833. return FALSE;
  2834. }
  2835. Entry->PatternSize = PatternSize;
  2836. INSERT_BEFORE(&(Entry->ListEntry), &(Set->PatternEntryList));
  2837. return TRUE;
  2838. }
  2839. VOID
  2840. ShDestroyCasePatternList (
  2841. PSHELL_NODE CaseNode
  2842. )
  2843. /*++
  2844. Routine Description:
  2845. This routine destroys the pattern sets in a case statement.
  2846. Arguments:
  2847. CaseNode - Supplies a pointer to the case statement.
  2848. Return Value:
  2849. None.
  2850. --*/
  2851. {
  2852. PSHELL_CASE_PATTERN_ENTRY Entry;
  2853. PSHELL_CASE_PATTERN_SET Set;
  2854. assert(CaseNode->Type == ShellNodeCase);
  2855. //
  2856. // Loop through every set in the case.
  2857. //
  2858. while (LIST_EMPTY(&(CaseNode->U.Case.PatternList)) == FALSE) {
  2859. Set = LIST_VALUE(CaseNode->U.Case.PatternList.Next,
  2860. SHELL_CASE_PATTERN_SET,
  2861. ListEntry);
  2862. LIST_REMOVE(&(Set->ListEntry));
  2863. if (Set->Action != NULL) {
  2864. ShReleaseNode(Set->Action);
  2865. }
  2866. //
  2867. // Loop through every entry in the set.
  2868. //
  2869. while (LIST_EMPTY(&(Set->PatternEntryList)) == FALSE) {
  2870. Entry = LIST_VALUE(Set->PatternEntryList.Next,
  2871. SHELL_CASE_PATTERN_ENTRY,
  2872. ListEntry);
  2873. LIST_REMOVE(&(Entry->ListEntry));
  2874. free(Entry->Pattern);
  2875. free(Entry);
  2876. }
  2877. free(Set);
  2878. }
  2879. return;
  2880. }
  2881. BOOL
  2882. ShAddComponentToCommand (
  2883. PSHELL_NODE Command,
  2884. PSTR Component,
  2885. UINTN ComponentSize
  2886. )
  2887. /*++
  2888. Routine Description:
  2889. This routine adds a component to a simple command string.
  2890. Arguments:
  2891. Command - Supplies a pointer to the simple command node.
  2892. Component - Supplies a pointer to the component string, either the command
  2893. or an argument.
  2894. ComponentSize - Supplies the size of the component string in bytes
  2895. including the null terminator.
  2896. Return Value:
  2897. TRUE on success.
  2898. FALSE on allocation failure.
  2899. --*/
  2900. {
  2901. BOOL Result;
  2902. PSHELL_NODE_SIMPLE_COMMAND SimpleCommand;
  2903. assert(Command->Type == ShellNodeSimpleCommand);
  2904. assert(ComponentSize != 0);
  2905. SimpleCommand = &(Command->U.SimpleCommand);
  2906. Result = ShStringAppend(&(SimpleCommand->Arguments),
  2907. &(SimpleCommand->ArgumentsSize),
  2908. &(SimpleCommand->ArgumentsBufferCapacity),
  2909. Component,
  2910. ComponentSize);
  2911. return Result;
  2912. }
  2913. BOOL
  2914. ShIsStringQuoted (
  2915. PSTR String
  2916. )
  2917. /*++
  2918. Routine Description:
  2919. This routine determines if any part of the given string is quoted, meaning
  2920. it has a backslash, single quote, or double quote character in it.
  2921. Arguments:
  2922. String - Supplies a pointer to the string to check.
  2923. Return Value:
  2924. TRUE if the string has a quoting character in it.
  2925. FALSE if the string is clean.
  2926. --*/
  2927. {
  2928. while (*String != '\0') {
  2929. if ((*String == SHELL_CONTROL_QUOTE) ||
  2930. (*String == SHELL_CONTROL_ESCAPE)) {
  2931. return TRUE;
  2932. }
  2933. String += 1;
  2934. }
  2935. return FALSE;
  2936. }
  2937. VOID
  2938. ShParseError (
  2939. PSHELL Shell,
  2940. PSHELL_NODE Node,
  2941. PSTR Format,
  2942. ...
  2943. )
  2944. /*++
  2945. Routine Description:
  2946. This routine prints a shell parse error to standard error.
  2947. Arguments:
  2948. Shell - Supplies a pointer to the shell.
  2949. Node - Supplies an optional pointer to the shell node being parsed.
  2950. Format - Supplies the printf style format string.
  2951. ... - Supplies the remaining arguments to the printf string.
  2952. Return Value:
  2953. TRUE if the string has a quoting character in it.
  2954. FALSE if the string is clean.
  2955. --*/
  2956. {
  2957. va_list ArgumentList;
  2958. ULONG LineNumber;
  2959. if (Node != NULL) {
  2960. LineNumber = Node->LineNumber;
  2961. } else {
  2962. LineNumber = Shell->Lexer.LineNumber;
  2963. }
  2964. fprintf(stderr, "sh: %d: ", LineNumber);
  2965. va_start(ArgumentList, Format);
  2966. vfprintf(stderr, Format, ArgumentList);
  2967. va_end(ArgumentList);
  2968. if (Shell->Lexer.TokenBufferSize != 0) {
  2969. //
  2970. // Make sure the buffer is null terminated, ideally not clobbering the
  2971. // valid part of the string.
  2972. //
  2973. if (Shell->Lexer.TokenBufferSize < Shell->Lexer.TokenBufferCapacity) {
  2974. Shell->Lexer.TokenBuffer[Shell->Lexer.TokenBufferSize] = '\0';
  2975. } else {
  2976. Shell->Lexer.TokenBuffer[Shell->Lexer.TokenBufferSize - 1] = '\0';
  2977. }
  2978. fprintf(stderr, " Token: %s.\n", Shell->Lexer.TokenBuffer);
  2979. } else {
  2980. fprintf(stderr, "\n");
  2981. }
  2982. return;
  2983. }