Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

849 lines
35 KiB

  1. /* SCCSID = %W% %E% */
  2. /*
  3. * Copyright Microsoft Corporation, 1983-1987
  4. *
  5. * This Module contains Proprietary Information of Microsoft
  6. * Corporation and should be treated as Confidential.
  7. */
  8. /****************************************************************
  9. * *
  10. * NEWCMD.C *
  11. * *
  12. * Support routines for command prompter. *
  13. * *
  14. ****************************************************************/
  15. #include <minlit.h> /* Types and constants */
  16. #include <bndtrn.h> /* The same */
  17. #include <bndrel.h> /* Types and constants */
  18. #include <lnkio.h> /* Linker I/O definitions */
  19. #include <lnkmsg.h> /* Error messages */
  20. #include <extern.h> /* External function declarations */
  21. /*
  22. * FUNCTION PROTOTYPES
  23. */
  24. LOCAL int NEAR GetInputByte(char *prompt);
  25. LOCAL BYTE NEAR GetStreamByte(char *prompt);
  26. LOCAL void NEAR SetUpCommandLine(int argc, char **argv);
  27. LOCAL void NEAR FinishCommandLine(void);
  28. #if AUTOVM
  29. BYTE FAR * NEAR FetchSym1(RBTYPE rb, WORD Dirty);
  30. #define FETCHSYM FetchSym1
  31. #else
  32. #define FETCHSYM FetchSym
  33. #endif
  34. #if OSMSDOS
  35. char *stackbuf;
  36. #endif
  37. LOCAL FTYPE fMoreCommandLine;
  38. /* More command line flag */
  39. LOCAL FTYPE fMoreIndirectFile;
  40. /* More-input-from-file flag */
  41. LOCAL BSTYPE bsIndir; /* File handle for indirect file */
  42. LOCAL FTYPE fEscNext;
  43. LOCAL FTYPE fNewLine = (FTYPE) TRUE;/* New command line */
  44. LOCAL FTYPE fStuffed; /* Put-back-character flag */
  45. LOCAL BYTE bStuffed; /* The character put back */
  46. LOCAL BYTE bSepLast; /* Last separator character */
  47. /* Char to replace spaces with */
  48. LOCAL FTYPE fRedirect; /* True iff stdin not a device */
  49. LOCAL WORD fQuotted; /* TRUE if inside " ... " */
  50. LOCAL char *pszRespFile; /* Pointer to responce file name */
  51. LOCAL char MaskedChar;
  52. #if TRUE
  53. #define SETCASE(c) (c) /* Leave as is */
  54. #else
  55. #define SETCASE(c) UPPER(c) /* Force to upper case */
  56. #endif
  57. #if WIN_3
  58. extern char far *fpszLinkCmdLine;
  59. #endif
  60. #if AUTOVM
  61. /*
  62. * HACK ALERT !!!!!!!!!!!!
  63. *
  64. * This function is repeated here becouse of mixed medium model.
  65. * This the same code as in NEWSYM.c but maked here LOCAL. This
  66. * allows near calls to this function in all segments, otherwise
  67. * function must be called as far.
  68. */
  69. extern short picur;
  70. /****************************************************************
  71. * *
  72. * FetchSym: *
  73. * *
  74. * This function fetches a symbol from the symbol table given *
  75. * its virtual address. The symbol may either be resident or *
  76. * in virtual memory. *
  77. * *
  78. ****************************************************************/
  79. BYTE FAR * NEAR FetchSym1(rb,fDirty)
  80. RBTYPE rb; /* Virtual address */
  81. WORD fDirty; /* Dirty page flag */
  82. {
  83. union {
  84. long vptr; /* Virtual pointer */
  85. BYTE FAR *fptr; /* Far pointer */
  86. struct {
  87. unsigned short offset;
  88. /* Offset value */
  89. unsigned short seg;
  90. } /* Segmnet value */
  91. ptr;
  92. }
  93. pointer; /* Different ways to describe pointer */
  94. pointer.fptr = rb;
  95. if(pointer.ptr.seg) /* If resident - segment value != 0 */
  96. {
  97. picur = 0; /* Picur not valid */
  98. return(pointer.fptr); /* Return pointer */
  99. }
  100. pointer.fptr = (BYTE FAR *) mapva(AREASYMS + (pointer.vptr << SYMSCALE),fDirty);
  101. /* Fetch from virtual memory */
  102. return(pointer.fptr);
  103. }
  104. #endif
  105. // Strip path from file spec - leave drive letter and filename
  106. void StripPath(BYTE *sb)
  107. {
  108. char Drive[_MAX_DRIVE];
  109. char Dir[_MAX_DIR];
  110. char Name[_MAX_FNAME];
  111. char Ext[_MAX_EXT];
  112. /* Decompose filename into four components */
  113. sb[sb[0]+1] = '\0';
  114. _splitpath(sb+1, Drive, Dir, Name, Ext);
  115. /* Create modified path name */
  116. _makepath(sb+1, Drive, NULL, Name, Ext);
  117. sb[0] = (BYTE) strlen(sb+1);
  118. }
  119. /****************************************************************
  120. * *
  121. * SetUpCommandLine: *
  122. * *
  123. * This function initializes the command line parser. *
  124. * *
  125. ****************************************************************/
  126. LOCAL void NEAR SetUpCommandLine(int argc,char **argv)
  127. {
  128. fMoreCommandLine = (FTYPE) ((argc - 1) != 0 ? TRUE : FALSE);
  129. /* If command line not empty */
  130. if (!_isatty(fileno(stdin))) /* Determine if stdin is a device */
  131. fRedirect = (FTYPE) TRUE;
  132. }
  133. /****************************************************************
  134. * *
  135. * FinishCommandLine: *
  136. * *
  137. * This function takes no arguments. If command input has *
  138. * been coming from a file, then this function closes that *
  139. * file; otherwise, it has no effect. It does not return a *
  140. * meaningful value. *
  141. * *
  142. ****************************************************************/
  143. LOCAL void NEAR FinishCommandLine(void) /* Close indirect file */
  144. {
  145. fflush(stdout); /* Force to screen */
  146. if(fMoreIndirectFile) /* If command input from file */
  147. {
  148. fMoreIndirectFile = FALSE; /* No more indirect file */
  149. fclose(bsIndir); /* Close indirect file */
  150. }
  151. }
  152. #if ECS
  153. /*
  154. * GetTxtChr : get the next character from a text file stream
  155. *
  156. * This routine handles mixed DBCS and ASCII characters as
  157. * follows:
  158. *
  159. * 1. The second byte of a DBCS character is returned in a
  160. * word with the high byte set to the lead byte of the character.
  161. * Thus the return value can be used in comparisions with
  162. * ASCII constants without being mistakenly matched.
  163. *
  164. * 2. A DBCS space character (0x8140) is returned as two
  165. * ASCII spaces (0x20). I.e. return a space the 1st and 2nd
  166. * times we're called.
  167. *
  168. * 3. ASCII characters and lead bytes of DBCS characters
  169. * are returned in the low byte of a word with the high byte
  170. * set to 0.
  171. */
  172. int GetTxtChr (bs)
  173. BSTYPE bs;
  174. {
  175. static int chBuf = -1; /* Character buffer */
  176. int next; /* The next byte */
  177. int next2; /* The one after that */
  178. /* -1 in chBuf means it doesn't contain a valid character */
  179. /* If we're not in the middle of a double-byte character,
  180. * get the next byte and process it.
  181. */
  182. if(chBuf == -1)
  183. {
  184. next = getc(bs);
  185. /* If this byte is a lead byte, get the following byte
  186. * and store both as a word in chBuf.
  187. */
  188. if(IsLeadByte(next))
  189. {
  190. next2 = getc(bs);
  191. chBuf = (next << 8) | next2;
  192. /* If the pair matches a DBCS space, set the return value
  193. * to ASCII space.
  194. */
  195. if(chBuf == 0x8140)
  196. next = 0x20;
  197. }
  198. }
  199. /* Else we're in the middle of a double-byte character. */
  200. else
  201. {
  202. /* If this is the 2nd byte of a DBCS space, set the return
  203. * value to ASCII space.
  204. */
  205. if(chBuf == 0x8140)
  206. next = 0x20;
  207. /* Else set the return value to the whole DBCS character */
  208. else
  209. next = chBuf;
  210. /* Reset the character buffer */
  211. chBuf = -1;
  212. }
  213. /* Return the next character */
  214. return(next);
  215. }
  216. #endif
  217. /****************************************************************
  218. * *
  219. * GetInputByte: *
  220. * *
  221. * This function takes as its input a pointer to an asciz *
  222. * string with which to prompt the user when more input is *
  223. * necessary. The function returns a byte of input. It *
  224. * checks to make sure the byte is a printable ascii character *
  225. * or a carriage return (^M). *
  226. * *
  227. ****************************************************************/
  228. LOCAL int NEAR GetInputByte(prompt)
  229. char *prompt; /* Pointer to prompt text */
  230. {
  231. REGISTER unsigned b; /* Input byte */
  232. #if ECS || defined(_MBCS)
  233. static FTYPE fInDBC; /* True iff in double-byte char */
  234. #endif
  235. if(fMoreIndirectFile) /* If input from file */
  236. {
  237. for(;;) /* Forever */
  238. {
  239. b = GetTxtChr(bsIndir); /* Read a byte */
  240. if(b == EOF || b == 032) break;
  241. /* Break on end of file */
  242. if(fNewLine) /* If at start of line */
  243. {
  244. if (prompt && !fNoEchoLrf)
  245. (*pfCputs)(prompt); /* Prompt the user */
  246. fNewLine = FALSE; /* Not at beginning anymore */
  247. }
  248. if (prompt && !fNoEchoLrf)
  249. {
  250. #if CRLF
  251. /* Allow both ^J and ^M^J to terminate input lines. */
  252. if(b == '\r') continue;
  253. if(b == '\n') (*pfCputc)('\r');
  254. #endif
  255. (*pfCputc)(SETCASE(b)); /* Output byte */
  256. }
  257. if(b == ';' && !fNoEchoLrf) NEWLINE(stdout);
  258. /* Follow escape by newline */
  259. else if(b == '\n') fNewLine = (FTYPE) TRUE;
  260. /* Look for new line */
  261. else if (b == '\t') b = ' ';
  262. /* Translate tabs to spaces */
  263. if(b == '\n' || b >= ' ') return(SETCASE(b));
  264. /* Return if valid char. */
  265. }
  266. FinishCommandLine(); /* Close indirect file */
  267. }
  268. if(fStuffed) /* If a byte saved */
  269. {
  270. fStuffed = FALSE; /* Now we're unstuffed */
  271. return(bStuffed); /* Return the stuffed byte */
  272. }
  273. if(fMoreCommandLine) /* If more command line */
  274. {
  275. for(;;) /* Forever */
  276. {
  277. if (*lpszCmdLine == '\0') /* If at end of command line */
  278. {
  279. fMoreCommandLine = FALSE;
  280. /* No more command line */
  281. fNewLine = (FTYPE) TRUE;/* New command line */
  282. return('\n'); /* Return '\n' */
  283. }
  284. b = (WORD) (*lpszCmdLine++);/* Get next character */
  285. if (b == '\\' && *lpszCmdLine == '"')
  286. { /* Skip escaped double quotes */
  287. lpszCmdLine++;
  288. if (*lpszCmdLine == '\0')
  289. {
  290. fMoreCommandLine = FALSE;
  291. /* No more command line */
  292. fNewLine = (FTYPE) TRUE;
  293. /* New command line */
  294. fQuotted = FALSE;
  295. return('\n'); /* Return '\n' */
  296. }
  297. else
  298. b = (WORD) (*lpszCmdLine++);
  299. }
  300. #if ECS || defined(_MBCS)
  301. /* If this is a trailing byte of a DBCS char, set the high
  302. * byte of b to nonzero, so b won't be confused with an ASCII
  303. * constant.
  304. */
  305. if (fInDBC)
  306. {
  307. b |= 0x100;
  308. fInDBC = FALSE;
  309. }
  310. else
  311. fInDBC = (FTYPE) IsLeadByte(b);
  312. #endif
  313. if (b >= ' ') return(SETCASE(b));
  314. /* Return if valid char. */
  315. }
  316. }
  317. for(;;) /* Forever */
  318. {
  319. if(fNewLine) /* If at start of line */
  320. {
  321. if(prompt && ((!fRedirect && !fNoprompt) || (!fEsc && fNoprompt)))
  322. /* If prompt and input from CON */
  323. (*pfCputs)(prompt); /* Prompt the user */
  324. fNewLine = FALSE; /* Not at beginning anymore */
  325. }
  326. b = GetTxtChr(stdin); /* Read a byte from terminal */
  327. if(b == EOF) b = ';'; /* Treat EOF like escape */
  328. else if (b == '\t') b = ' '; /* Treat tab like space */
  329. if(b == '\n') fNewLine = (FTYPE) TRUE; /* New line */
  330. if(b == '\n' || b >= ' ') return(SETCASE(b));
  331. /* Return if character is valid */
  332. }
  333. }
  334. /****************************************************************
  335. * *
  336. * GetStreamByte: *
  337. * *
  338. * This function takes as its input a pointer to a string of *
  339. * text with which to prompt the user, if necessary. It *
  340. * returns a byte of command input, and opens an indirect file *
  341. * to do so if necessary. *
  342. * *
  343. ****************************************************************/
  344. LOCAL BYTE NEAR GetStreamByte(prompt)
  345. char *prompt; /* Pointer to text of prompt */
  346. {
  347. REGISTER WORD ich; /* Index variable */
  348. SBTYPE filnam; /* File name buffer */
  349. WORD b; /* A byte */
  350. #if OSMSDOS
  351. extern char *stackbuf;
  352. #endif
  353. if (((b = (WORD)GetInputByte(prompt)) == INDIR) && !fQuotted)
  354. { /* If user specifies indirect file */
  355. if (fMoreIndirectFile) Fatal(ER_nestrf);
  356. /* Check for nesting */
  357. DEBUGMSG("Getting response file name");
  358. /* Debug message */
  359. ich = 0; /* Initialize index */
  360. while(ich < SBLEN - 1) /* Loop to get file name */
  361. {
  362. b = (WORD)GetInputByte((char *) 0);
  363. /* Read in a byte */
  364. fQuotted = fQuotted ? b != '"' : b == '"';
  365. if ((!fQuotted && (b == ',' || b == '+' || b == ';' || b == ' ')) ||
  366. b == CHSWITCH || b < ' ') break;
  367. /* Exit loop on non-name char. */
  368. if (b != '"')
  369. filnam[ich++] = (char) b;
  370. /* Store in file name */
  371. }
  372. if(b > ' ') /* If legal input character */
  373. {
  374. fStuffed = (FTYPE) TRUE; /* Set flag */
  375. bStuffed = (BYTE) b; /* Save character */
  376. }
  377. filnam[ich] = '\0'; /* Null-terminate file name */
  378. pszRespFile = _strdup(filnam); /* Duplicate file name */
  379. DEBUGMSG(filnam); /* Debug message */
  380. if((bsIndir = fopen(filnam,RDTXT)) == NULL)
  381. Fatal(ER_opnrf,filnam);
  382. #if OSMSDOS
  383. setvbuf(bsIndir,stackbuf,_IOFBF,512);
  384. #endif
  385. fMoreIndirectFile = (FTYPE) TRUE;/* Take input from file now */
  386. b = (WORD)GetInputByte(prompt); /* Read a byte */
  387. DEBUGVALUE(b); /* Debug info */
  388. }
  389. return((BYTE) b); /* Return a byte */
  390. }
  391. /****************************************************************
  392. * *
  393. * GetLine: *
  394. * *
  395. * This function takes as its arguments the address of a *
  396. * buffer in which to return a line of command text and a *
  397. * pointer to a string with which to prompt the user, if *
  398. * necessary. In addition to reading a line, this function *
  399. * will set the global flag fEsc to true if the next *
  400. * character to be read is a semicolon. The function does not *
  401. * return a meaningful value. *
  402. * *
  403. ****************************************************************/
  404. void NEAR GetLine(pcmdlin,prompt) /* Get a command line */
  405. BYTE *pcmdlin; /* Pointer to destination string */
  406. char *prompt; /* Pointer to text of prompt string */
  407. {
  408. REGISTER WORD ich; /* Index */
  409. WORD ich1; /* Index */
  410. WORD ich2; /* Index */
  411. BYTE b; /* A byte of input */
  412. WORD fFirstTime; /* Boolean */
  413. fFirstTime = (FTYPE) TRUE; /* Assume it is our first time */
  414. bSepLast = bSep; /* Save last separator */
  415. if(fEscNext) /* If escape character next */
  416. {
  417. pcmdlin[0] = '\0'; /* No command line */
  418. fEsc = (FTYPE) TRUE; /* Set global flag */
  419. return; /* That's all for now */
  420. }
  421. for(;;) /* Forever */
  422. {
  423. fQuotted = FALSE;
  424. ich = 0; /* Initialize index */
  425. while(ich < SBLEN - 1) /* While room in buffer */
  426. {
  427. b = GetStreamByte(prompt); /* Get a byte */
  428. fQuotted = fQuotted ? b != '"' : b == '"';
  429. if (b == '\n' || (!fQuotted && (b == ',' || b == ';')))
  430. {
  431. if (b == ';')
  432. fMoreCommandLine = FALSE;
  433. break; /* Leave loop on end of line */
  434. }
  435. if (!(b == ' ' && ich == 0))/* Store if not a leading space */
  436. {
  437. if (!fQuotted)
  438. {
  439. if (b == '+')
  440. {
  441. if (!MaskedChar)
  442. MaskedChar = b;
  443. b = chMaskSpace;
  444. }
  445. if (b == ' ' && !MaskedChar)
  446. MaskedChar = b;
  447. }
  448. pcmdlin[++ich] = b;
  449. }
  450. }
  451. /*
  452. * If ich==SBLEN-1, last char cannot have been a line terminator
  453. * and buffer is full. If next input char is a line terminator,
  454. * OK, else error.
  455. */
  456. if(ich == SBLEN - 1 && (b = GetStreamByte(prompt)) != '\n' &&
  457. b != ',' && b != ';')
  458. {
  459. fflush(stdout);
  460. Fatal(ER_linmax);
  461. }
  462. while(ich) /* Loop to trim trailing spaces */
  463. {
  464. if(pcmdlin[ich] != ' ') break;
  465. /* Break on non-space */
  466. --ich; /* Decrement count */
  467. }
  468. ich1 = 0; /* Initialize */
  469. ich2 = 0; /* Initialize */
  470. while(ich2 < ich) /* Loop to remove or replace spaces */
  471. {
  472. ++ich2;
  473. if (pcmdlin[ich2] == '"')
  474. {
  475. // Start of quotted file name
  476. while (ich2 < ich && pcmdlin[++ich2] != '"')
  477. pcmdlin[++ich1] = pcmdlin[ich2];
  478. }
  479. else if (pcmdlin[ich2] != ' ' || chMaskSpace != 0 || fQuotted)
  480. { /* If not space or replacing spaces */
  481. ++ich1;
  482. if(!fQuotted && pcmdlin[ich2] == ' ') pcmdlin[ich1] = chMaskSpace;
  483. /* Replace space if replacing */
  484. else pcmdlin[ich1] = pcmdlin[ich2];
  485. /* Else copy the non-space */
  486. }
  487. }
  488. pcmdlin[0] = (BYTE) ich1; /* Set the length */
  489. bSep = b; /* Save the separator */
  490. if (ich ||
  491. !fFirstTime ||
  492. !((bSepLast == ',' && bSep == '\n') ||
  493. (bSepLast == '\n' && bSep == ',')))
  494. break; /* Exit the loop */
  495. fFirstTime = FALSE; /* No the first time */
  496. bSepLast = ','; /* Comma is the field separator */
  497. }
  498. fEscNext = (FTYPE) (b == ';'); /* Set flag */
  499. fEsc = (FTYPE) (!ich && fEscNext); /* Set flag */
  500. }
  501. /****************************************************************
  502. * *
  503. * ParseCmdLine: *
  504. * *
  505. * This function takes no arguments and returns no meaningful *
  506. * value. It parses the command line. *
  507. * *
  508. ****************************************************************/
  509. void ParseCmdLine(argc,argv)
  510. /* Parse the command line */
  511. int argc; /* Count of arguments */
  512. char **argv; /* Argument vector */
  513. {
  514. SBTYPE sbFile; /* File name */
  515. SBTYPE sbPrompt; /* Prompt text */
  516. SBTYPE rgb; /* Command line buffer */
  517. FTYPE fMoreInput; /* More input flag */
  518. FTYPE fFirstTime;
  519. AHTEPTR pahte; /* Pointer to hash table entry */
  520. FTYPE fNoList; /* True if no list file */
  521. BYTE *p;
  522. WORD i;
  523. #if OSMSDOS
  524. char buf[512]; /* File buffer */
  525. extern char *stackbuf;
  526. stackbuf = buf;
  527. #endif
  528. #if WIN_3
  529. lpszCmdLine = fpszLinkCmdLine;
  530. #endif
  531. SetUpCommandLine(argc,argv); /* Initialize command line */
  532. chMaskSpace = 0x1f;
  533. bsLst = stdout; /* Assume listing to console */
  534. fLstFileOpen = (FTYPE) TRUE; /* So Fatal will flush it */
  535. fFirstTime = fMoreCommandLine;
  536. do /* Do while more input */
  537. {
  538. fMoreInput = FALSE; /* Assume no more input */
  539. if (fFirstTime)
  540. GetLine(rgb, NULL);
  541. else
  542. GetLine(rgb, strcat(strcpy(sbPrompt,GetMsg(P_objprompt)), " [.obj]: "));
  543. /* Get a line of command text */
  544. if(!rgb[0]) break; /* Break if length 0 */
  545. if(rgb[B2W(rgb[0])] == chMaskSpace) /* If last char is chMaskSpace */
  546. {
  547. fMoreInput = (FTYPE) TRUE; /* More to come */
  548. --rgb[0]; /* Decrement the length */
  549. }
  550. BreakLine(rgb,ProcObject,chMaskSpace); /* Apply ProcObject() to line */
  551. #if CMDMSDOS
  552. if (fFirstTime && !fNoBanner)
  553. DisplayBanner(); /* Display signon banner */
  554. #endif
  555. if (fFirstTime && !fNoEchoLrf)
  556. {
  557. if (fMoreInput || (fMoreIndirectFile && fFirstTime))
  558. {
  559. (*pfCputs)(strcat(strcpy(sbPrompt,GetMsg(P_objprompt)), " [.obj]: "));
  560. /* Prompt the user */
  561. rgb[B2W(rgb[0]) + 2] = '\0';
  562. if (fMoreIndirectFile)
  563. {
  564. if (!fMoreInput && !fNewLine && !fEscNext)
  565. rgb[B2W(rgb[0]) + 1] = ',';
  566. else if (!fMoreInput && fNewLine)
  567. rgb[B2W(rgb[0]) + 1] = ' ';
  568. else if (rgb[B2W(rgb[0]) + 1] == chMaskSpace)
  569. rgb[B2W(rgb[0]) + 1] = '+';
  570. }
  571. else if (rgb[B2W(rgb[0]) + 1] == chMaskSpace)
  572. rgb[B2W(rgb[0]) + 1] = '+';
  573. for (i = 1; i <= rgb[0]; i++)
  574. if (rgb[i] == chMaskSpace)
  575. rgb[i] = MaskedChar;
  576. (*pfCputs)(&rgb[1]); /* And display his response */
  577. if (fMoreInput || fNewLine || fEscNext)
  578. if (!fNoEchoLrf)
  579. NEWLINE(stdout);
  580. }
  581. }
  582. fFirstTime = FALSE;
  583. }
  584. while(fMoreInput); /* End of loop */
  585. #if OVERLAYS
  586. if(fInOverlay) Fatal(ER_unmlpar);
  587. /* Check for parenthesis error
  588. * See ProcObject() to find out
  589. * what is going on here.
  590. */
  591. #endif
  592. chMaskSpace = 0; /* Remove spaces */
  593. if(rhteFirstObject == RHTENIL) Fatal(ER_noobj);
  594. /* There must be some objects */
  595. #if OEXE
  596. pahte = (AHTEPTR ) FETCHSYM(rhteFirstObject,FALSE);
  597. /* Fetch name of first object */
  598. memcpy(sbFile,GetFarSb(pahte->cch),B2W(pahte->cch[0]) + 1);
  599. /* Copy name of first object */
  600. #if ODOS3EXE
  601. if(fQlib)
  602. UpdateFileParts(sbFile,sbDotQlb);
  603. else if (fBinary)
  604. UpdateFileParts(sbFile,sbDotCom);/* Force extension to .COM */
  605. else
  606. #endif
  607. UpdateFileParts(sbFile,sbDotExe);/* Force extension to .EXE */
  608. #endif
  609. #if OIAPX286
  610. memcpy(sbFile,"\005a.out",6); /* a.out is default for Xenix */
  611. #endif
  612. #if OSMSDOS
  613. if(sbFile[2] == ':') sbFile[1] = (BYTE) (DskCur + 'a');
  614. /* Get drive letter of default drive */
  615. StripPath(sbFile); /* Strip off path specification */
  616. #endif
  617. bufg[0] = 0;
  618. if(!fEsc) /* If command not escaped */
  619. {
  620. strcat(strcpy(sbPrompt, GetMsg(P_runfile)), " [");
  621. sbFile[1 + sbFile[0]] = '\0';
  622. /* Build run file prompt */
  623. /* Prompt for run file */
  624. GetLine(bufg, strcat(strcat(sbPrompt, &sbFile[1]), "]: "));
  625. PeelFlags(bufg); /* Peel flags */
  626. if (B2W(bufg[0]))
  627. memcpy(sbFile,bufg,B2W(bufg[0]) + 1);
  628. /* Store user responce */
  629. else
  630. {
  631. // Store only base name without extension
  632. sbFile[0] -= 4;
  633. }
  634. }
  635. EnterName(sbFile,ATTRNIL,TRUE); /* Create hash tab entry for name */
  636. rhteRunfile = vrhte; /* Save hash table address */
  637. #if OSMSDOS
  638. if (sbFile[0] >= 2 && sbFile[2] == ':')
  639. chRunFile = sbFile[1]; /* If disk specified, use it */
  640. else
  641. chRunFile = (BYTE) (DskCur + 'a');/* Else use current disk */
  642. #endif
  643. fNoList = (FTYPE) (!vfMap && !vfLineNos); /* Set default flag value */
  644. #if OSMSDOS
  645. memcpy(sbFile,"\002a:",3); /* Start with a drive spec */
  646. #else
  647. sbFile[0] = '\0'; /* Null name */
  648. #endif
  649. pahte = (AHTEPTR ) FETCHSYM(vrhte,FALSE);
  650. /* Fetch run file name */
  651. UpdateFileParts(sbFile,GetFarSb(pahte->cch)); /* Use .EXE file name... */
  652. UpdateFileParts(sbFile,sbDotMap); /* ...with .MAP extension */
  653. #if OSMSDOS
  654. sbFile[1] = (BYTE) (DskCur + 'a'); /* Default to default drive */
  655. StripPath(sbFile); /* Strip off path specification */
  656. #endif
  657. fNoList = (FTYPE) (!vfMap && !vfLineNos); /* No list if not /M and not /LI */
  658. if(!fEsc) /* If argument not defaulted */
  659. {
  660. if(bSep == ',') fNoList = FALSE;/* There will be a list file */
  661. if(fNoList) /* If no list file yet */
  662. {
  663. #if OSMSDOS
  664. memcpy(sbFile,"\007nul.map",8);
  665. /* Default null list name */
  666. #endif
  667. #if OSXENIX
  668. memcpy(sbFile,"\007nul.map",8);
  669. /* Default null list name */
  670. #endif
  671. }
  672. strcat(strcpy(sbPrompt, GetMsg(P_listfile)), " [");
  673. sbFile[1 + sbFile[0]] = '\0';
  674. GetLine(rgb, strcat(strcat(sbPrompt, &sbFile[1]), "]: "));
  675. /* Get map file name */
  676. PeelFlags(rgb); /* Process any flags */
  677. if(rgb[0]) /* If name given */
  678. {
  679. fNoList = FALSE; /* There will (maybe) be a list file */
  680. UpdateFileParts(sbFile,rgb);
  681. }
  682. }
  683. chMaskSpace = 0x1f; /* Change spaces to chMaskSpaces */
  684. if(!fEsc) /* If argument not defaulted */
  685. {
  686. strcat(strcpy(sbPrompt,GetMsg(P_libprompt)), " [.lib]: ");
  687. do /* Loop to get library names */
  688. {
  689. fMoreInput = FALSE; /* Assume no more input */
  690. GetLine(rgb, sbPrompt);
  691. if(fEsc || !rgb[0]) break; /* Exit loop if no more input */
  692. if(rgb[B2W(rgb[0])] == chMaskSpace) /* If more to come */
  693. {
  694. fMoreInput = (FTYPE) TRUE; /* Set flag to true */
  695. --rgb[0]; /* Decrement length */
  696. }
  697. BreakLine(rgb,AddLibrary,chMaskSpace);
  698. /* Apply AddLibrary() to lib name(s) */
  699. }
  700. while(fMoreInput); /* End of loop */
  701. }
  702. #if OSEGEXE AND NOT QCLINK
  703. chMaskSpace = 0; /* Remove spaces */
  704. rhteDeffile = RHTENIL; /* Assume no definitions file */
  705. if(!fEsc) /* If argument not defaulted */
  706. {
  707. #if OSMSDOS
  708. GetLine(rgb, strcat(strcpy(sbPrompt,GetMsg(P_defprompt)), " [nul.def]: "));
  709. /* Get def file name */
  710. memcpy(sbPrompt,"\007nul.def",8); /* Default null definition file name */
  711. #endif
  712. #if OSXENIX
  713. GetLine(rgb, strcat(strcpy(sbPrompt,GetMsg(P_defprompt)), " [nul.def]: "));
  714. /* Get def file name */
  715. memcpy(sbPrompt,"\007nul.def",8); /* Default null definition file name */
  716. #endif
  717. PeelFlags(rgb); /* Process any flags */
  718. if(rgb[0]) /* If a name was given */
  719. {
  720. UpdateFileParts(sbPrompt,rgb);
  721. /* Get file name */
  722. memcpy(rgb,sbPrompt,B2W(sbPrompt[0]) + 1);
  723. /* Copy name */
  724. UpdateFileParts(rgb,"\003NUL");
  725. /* Replace name with null name */
  726. if(!SbCompare(sbPrompt,rgb,TRUE))
  727. { /* If name not null */
  728. EnterName(sbPrompt,ATTRNIL,TRUE);
  729. /* Create hash tab entry for name */
  730. rhteDeffile = vrhte; /* Save hash table address */
  731. }
  732. }
  733. }
  734. #endif /* OSEGEXE */
  735. FinishCommandLine(); /* Close indirect file (if any) */
  736. fLstFileOpen = FALSE;
  737. #if OSMSDOS
  738. rhteLstfile = RHTENIL; /* Assume no list file */
  739. #endif
  740. if(!fNoList) /* If a listing wanted */
  741. {
  742. memcpy(sbPrompt,sbFile,B2W(sbFile[0]) + 1);
  743. /* Copy full file name */
  744. UpdateFileParts(sbPrompt,"\003NUL");
  745. /* Change name only */
  746. if(!SbCompare(sbFile,sbPrompt,TRUE))
  747. { /* If name given not null device */
  748. UpdateFileParts(sbPrompt,"\003CON");
  749. /* Change name only */
  750. if(!SbCompare(sbFile,sbPrompt,TRUE))
  751. { /* If list file not console */
  752. sbFile[B2W(++sbFile[0])] = '\0';
  753. /* Null-terminate name */
  754. if((bsLst = fopen(&sbFile[1],WRBIN)) == NULL)
  755. Fatal(ER_lstopn); /* Open listing file */
  756. #if OSMSDOS
  757. #ifdef M_I386
  758. if((p = GetMem(512)) != NULL)
  759. #else
  760. if((p = malloc(512)) != NULL)
  761. #endif
  762. setvbuf(bsLst,p,_IOFBF,512);
  763. EnterName(sbFile,ATTRNIL,TRUE);
  764. /* Create hash tab entry for name */
  765. rhteLstfile = vrhte; /* Save hash table address */
  766. #endif
  767. }
  768. else bsLst = stdout; /* Else list to console */
  769. #if OSMSDOS
  770. if(bsLst == stdout) chListFile = (unsigned char) '\377';
  771. /* List file is console */
  772. else if(_isatty(fileno(bsLst))) chListFile = (unsigned char) '\377';
  773. /* List file is some device */
  774. else if(sbFile[2] == ':') /* Else if drive spec given */
  775. chListFile = (BYTE) (sbFile[1] - 'a');
  776. /* Save floppy drive number */
  777. else chListFile = DskCur; /* Else list file on current floppy */
  778. #endif
  779. fLstFileOpen = (FTYPE) TRUE;/* We have a list file */
  780. }
  781. }
  782. #if FALSE AND OSMSDOS AND OWNSTDIO
  783. /* If wer're using our own stdio, set stdout to unbuffered if it
  784. * goes to console.
  785. * CAN'T do this because we now use standard fprintf. Only
  786. * stdio is custom made.
  787. */
  788. if(_isatty(fileno(stdout)))
  789. {
  790. fflush(stdout);
  791. stdout->_flag |= _IONBF;
  792. }
  793. #endif
  794. #if QCLINK OR Z2_ON
  795. if (fZ2 && pszRespFile != NULL)
  796. _unlink(pszRespFile);
  797. if (pszRespFile != NULL)
  798. FFREE(pszRespFile);
  799. #endif
  800. }