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

1166 lines
23 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. dnutil.c
  5. Abstract:
  6. Miscellaneous routines for DOS-hosted NT setup program.
  7. Author:
  8. Ted Miller (tedm) 30-March-1992
  9. Revision History:
  10. --*/
  11. #include "winnt.h"
  12. #include <string.h>
  13. #include <process.h>
  14. #include <malloc.h>
  15. #include <dos.h>
  16. #include <direct.h>
  17. #include <ctype.h>
  18. BOOLEAN WarnedAboutSkip = FALSE;
  19. ULONG
  20. DnGetKey(
  21. VOID
  22. )
  23. /*++
  24. Routine Description:
  25. Waits for any keypress.
  26. Arguments:
  27. None.
  28. Return Value:
  29. Actual key pressed.
  30. --*/
  31. {
  32. USHORT c;
  33. #if NEC_98
  34. _asm {
  35. xor ax,ax // function: read char from keyboard
  36. int 18h
  37. mov c,ax
  38. }
  39. switch(c) {
  40. case 0x3d00: // down arrow
  41. return(DN_KEY_DOWN);
  42. case 0x3a00: // up arrow
  43. return(DN_KEY_UP);
  44. case 0x3e00: // home
  45. return(DN_KEY_HOME);
  46. case 0x3f00: // end
  47. return(DN_KEY_END);
  48. case 0x3600: // page up
  49. return(DN_KEY_PAGEUP);
  50. case 0x3700: // page down
  51. return(DN_KEY_PAGEDOWN);
  52. case 0x6200: // F1
  53. return(DN_KEY_F1);
  54. case 0x6300: // F2
  55. return(DN_KEY_F2);
  56. case 0x6400: // F3
  57. return(DN_KEY_F3);
  58. case 0x6500: // F4
  59. return(DN_KEY_F4);
  60. default:
  61. return((ULONG)(c & ((c & 0x00ff) ? 0x00ff : 0xffff)));
  62. }
  63. #else // NEC_98
  64. _asm {
  65. mov ah,0 // function: read char from keyboard
  66. int 16h
  67. mov c,ax
  68. }
  69. switch(c) {
  70. case 0x5000: // down arrow
  71. return(DN_KEY_DOWN);
  72. case 0x4800: // up arrow
  73. return(DN_KEY_UP);
  74. case 0x4700: // home
  75. return(DN_KEY_HOME);
  76. case 0x4f00: // end
  77. return(DN_KEY_END);
  78. case 0x4900: // page up
  79. return(DN_KEY_PAGEUP);
  80. case 0x5100: // page down
  81. return(DN_KEY_PAGEDOWN);
  82. case 0x3b00: // F1
  83. return(DN_KEY_F1);
  84. case 0x3c00: // F2
  85. return(DN_KEY_F2);
  86. case 0x3d00: // F3
  87. return(DN_KEY_F3);
  88. case 0x3e00: // F4
  89. return(DN_KEY_F4);
  90. default:
  91. return((ULONG)(c & ((c & 0x00ff) ? 0x00ff : 0xffff)));
  92. }
  93. #endif // NEC_98
  94. }
  95. ULONG
  96. DnGetValidKey(
  97. IN PULONG ValidKeyList
  98. )
  99. /*++
  100. Routine Description:
  101. Waits for a keypress matching one of the values given in a list.
  102. The list must be terminated with a 0 entry.
  103. Arguments:
  104. ValidKeyList - valid keys.
  105. Return Value:
  106. Actual key pressed.
  107. --*/
  108. {
  109. ULONG key;
  110. int i;
  111. while(1) {
  112. key = DnGetKey();
  113. for(i=0; ValidKeyList[i]; i++) {
  114. if(key == ValidKeyList[i]) {
  115. return(key);
  116. }
  117. }
  118. }
  119. }
  120. VOID
  121. vDnDisplayScreen(
  122. IN PSCREEN Screen,
  123. IN va_list arglist
  124. )
  125. /*++
  126. Routine Description:
  127. Displays a screen.
  128. Arguments:
  129. Screen - supplies pointer to structure describing screen to display.
  130. arglist - supplies list of arguments for printf-style formatting.
  131. Return Value:
  132. None.
  133. --*/
  134. {
  135. UCHAR y;
  136. PCHAR p;
  137. PCHAR CurrentLine;
  138. int i;
  139. static CHAR FormatString[1600],FormattedString[1600];
  140. //
  141. // Take each line in the screen and put in into a buffer, to form
  142. // one large string. Place newlines at the end of each string.
  143. //
  144. for(FormatString[0]=0,i=0; Screen->Strings[i]; i++) {
  145. if(strlen(FormatString)+strlen(Screen->Strings[i])+2 < sizeof(FormatString)) {
  146. strcat(FormatString,Screen->Strings[i]);
  147. strcat(FormatString,"\n");
  148. } else {
  149. break;
  150. }
  151. }
  152. //
  153. // Format the string using given arguments.
  154. //
  155. vsprintf(FormattedString,FormatString,arglist);
  156. for(y=Screen->Y,CurrentLine=FormattedString; CurrentLine && *CurrentLine; y++) {
  157. if(p = strchr(CurrentLine,'\n')) {
  158. *p = 0;
  159. }
  160. DnPositionCursor(Screen->X,y);
  161. DnWriteString(CurrentLine);
  162. CurrentLine = p ? p+1 : NULL;
  163. }
  164. }
  165. VOID
  166. DnDisplayScreen(
  167. IN PSCREEN Screen,
  168. ...
  169. )
  170. /*++
  171. Routine Description:
  172. Displays a screen.
  173. Arguments:
  174. Screen - supplies pointer to structure describing screen to display.
  175. Return Value:
  176. None.
  177. --*/
  178. {
  179. va_list arglist;
  180. va_start(arglist,Screen);
  181. vDnDisplayScreen(Screen,arglist);
  182. va_end(arglist);
  183. }
  184. VOID
  185. DnFatalError(
  186. IN PSCREEN Screen,
  187. ...
  188. )
  189. /*++
  190. Routine Description:
  191. Displays a fatal error screen and prompts the user to press enter
  192. to exit. DOES NOT RETURN.
  193. Arguments:
  194. Screen - supplies pointer to structure describing screen to display.
  195. Return Value:
  196. DOES NOT RETURN.
  197. --*/
  198. {
  199. ULONG ExitOnlyKeyList[2] = { ASCI_CR,0 };
  200. va_list arglist;
  201. int i;
  202. DnClearClientArea();
  203. DnWriteStatusText(DntEnterEqualsExit);
  204. va_start(arglist,Screen);
  205. vDnDisplayScreen(Screen,arglist);
  206. va_end(arglist);
  207. for(i=0; Screen->Strings[i]; i++);
  208. DnPositionCursor(Screen->X,(UCHAR)(Screen->Y + i + 1));
  209. DnWriteString(DntPressEnterToExit);
  210. DnGetValidKey(ExitOnlyKeyList);
  211. DnExit(1);
  212. }
  213. BOOLEAN
  214. DnCopyError(
  215. IN PCHAR Filename,
  216. IN PSCREEN ErrorScreen,
  217. IN int FilenameLine
  218. )
  219. /*++
  220. Routine Description:
  221. Displays a screen informing the user that there has been an error copying
  222. a file, and allows the options of continuing or exiting Setup.
  223. Arguments:
  224. Filename - supplies name of source file which could not be copied.
  225. ErrorScreen - supplies the text to label the error.
  226. FilenameLine - supplies line number on the ErrorScreen in which the
  227. filename should be displayed.
  228. Return Value:
  229. TRUE if user elects to retry; FALSE if user elects to continue;
  230. does not return if user chooses to exit.
  231. --*/
  232. {
  233. ULONG KeyList[4] = { ASCI_CR,DN_KEY_F3,ASCI_ESC,0 };
  234. ULONG KeyList2[4] = { 0,0,ASCI_CR,0 };
  235. KeyList2[0] = DniAccelSkip1;
  236. KeyList2[1] = DniAccelSkip2;
  237. DnClearClientArea();
  238. DnWriteStatusText("%s %s %s",DntEnterEqualsRetry,DntEscEqualsSkipFile,DntF3EqualsExit);
  239. ErrorScreen->Strings[FilenameLine] = Filename;
  240. DnDisplayScreen(ErrorScreen);
  241. while(1) {
  242. switch(DnGetValidKey(KeyList)) {
  243. case DN_KEY_F3:
  244. DnExitDialog();
  245. break;
  246. case ASCI_CR:
  247. return(TRUE); // retry
  248. case ASCI_ESC:
  249. if(!WarnedAboutSkip) {
  250. DnClearClientArea();
  251. DnDisplayScreen(&DnsSureSkipFile);
  252. DnWriteStatusText("%s %s",DntEnterEqualsRetry,DntXEqualsSkipFile);
  253. if(DnGetValidKey(KeyList2) == ASCI_CR) {
  254. //
  255. // retry
  256. //
  257. return(TRUE);
  258. } else {
  259. //
  260. // User elected to skip: prevent future warnings.
  261. //
  262. WarnedAboutSkip = TRUE;
  263. }
  264. }
  265. return(FALSE); // skip file
  266. }
  267. }
  268. }
  269. PCHAR
  270. DnDupString(
  271. IN PCHAR String
  272. )
  273. /*++
  274. Routine Description:
  275. Duplicate a string. Do not return if not enough memory.
  276. Arguments:
  277. String - string to be duplicated
  278. Return Value:
  279. Pointer to new string. Does not return if insufficient memory.
  280. --*/
  281. {
  282. if( String ) {
  283. PCHAR p = MALLOC(strlen(String)+1,TRUE);
  284. return(strcpy(p,String));
  285. } else {
  286. return( NULL );
  287. }
  288. }
  289. VOID
  290. DnGetString(
  291. IN OUT PCHAR String,
  292. IN UCHAR X,
  293. IN UCHAR Y,
  294. IN UCHAR W
  295. )
  296. /*++
  297. Routine Description:
  298. Allow the user to type a string in an edit field. Interpret F3
  299. to allow him to exit.
  300. Arguments:
  301. String - on input, supplies the default string. On output, contains
  302. the string entered by the user.
  303. X,Y - coords of leftmost char of edit field.
  304. W - width of edit field, and maximum length of the string.
  305. Return Value:
  306. None.
  307. --*/
  308. {
  309. ULONG key;
  310. int Position = strlen(String);
  311. DnStartEditField(TRUE,X,Y,W);
  312. DnPositionCursor(X,Y);
  313. DnWriteString(String);
  314. DnPositionCursor((UCHAR)(X+Position),Y);
  315. while(1) {
  316. key = DnGetKey();
  317. switch(key) {
  318. case DN_KEY_F3:
  319. DnExitDialog();
  320. break;
  321. case ASCI_BS:
  322. if(Position) {
  323. String[--Position] = 0;
  324. DnPositionCursor((UCHAR)(X+Position),Y);
  325. DnWriteChar(' ');
  326. }
  327. break;
  328. case ASCI_ESC:
  329. Position = 0;
  330. String[0] = 0;
  331. DnStartEditField(TRUE,X,Y,W); // blanks edit field
  332. DnPositionCursor(X,Y);
  333. break;
  334. case ASCI_CR:
  335. DnStartEditField(FALSE,X,Y,W);
  336. return;
  337. default:
  338. if(((UCHAR)Position < W) && !(key & 0xffffff00)) {
  339. DnWriteChar((CHAR)key);
  340. String[Position++] = (CHAR)key;
  341. String[Position] = 0;
  342. DnPositionCursor((UCHAR)(X+Position),Y);
  343. }
  344. }
  345. }
  346. }
  347. BOOLEAN
  348. DnIsDriveValid(
  349. IN unsigned Drive
  350. )
  351. /*++
  352. Routine Description:
  353. Determine whether a drive is valid (ie, exists and is accessible).
  354. Arguments:
  355. Drive - drive (1=A, 2=B, etc).
  356. Return Value:
  357. TRUE if drive is valid.
  358. FALSE if not.
  359. --*/
  360. {
  361. int CurrentDrive = _getdrive();
  362. int Status;
  363. //
  364. // We'll make the determination of whether the drive is valid by
  365. // attempting to switch to it. If this succeeds, assume the drive
  366. // is valid.
  367. //
  368. Status = _chdrive(Drive);
  369. _chdrive(CurrentDrive);
  370. return((BOOLEAN)(Status == 0));
  371. }
  372. BOOLEAN
  373. DnIsDriveRemote(
  374. IN unsigned Drive,
  375. OUT PCHAR UncPath OPTIONAL
  376. )
  377. /*++
  378. Routine Description:
  379. Determine whether a drive is remote and optionally retrieve the
  380. UNC path of the target.
  381. Arguments:
  382. Drive - drive (1=A, 2=B, etc).
  383. UncPath - if specified and the drive is a network drive, the
  384. UNC path the drive is connected to is returned in this buffer.
  385. The caller must make sure the buffer is large enough (128 bytes).
  386. If this string is empty then the unc path could not be determined.
  387. Return Value:
  388. TRUE if drive is remote.
  389. FALSE if not (or we couldn't determine whether the drive is remote).
  390. --*/
  391. {
  392. union REGS RegIn,RegOut;
  393. BOOLEAN OK;
  394. CHAR LocalBuffer[16];
  395. unsigned LocalBufferOffset;
  396. unsigned Index;
  397. //
  398. // Call IOCTL function 09.
  399. // If carry set (error), assume not remote.
  400. // If no error, bit 12 of dx set if remote.
  401. //
  402. RegIn.x.ax = 0x4409;
  403. RegIn.h.bl = (unsigned char)Drive;
  404. intdos(&RegIn,&RegOut);
  405. if(!RegOut.x.cflag && (RegOut.x.dx & 0x1000)) {
  406. if(UncPath) {
  407. //
  408. // If we don't do this and try instead to use
  409. // offset LocalBuffer inside the _asm block
  410. // we get the wrong address.
  411. //
  412. LocalBufferOffset = (unsigned)LocalBuffer;
  413. Index = 0;
  414. do {
  415. OK = TRUE;
  416. _asm {
  417. push ds
  418. push es
  419. mov ax,0x5f02
  420. mov bx,Index
  421. mov cx,word ptr [UncPath+2]
  422. mov di,word ptr [UncPath]
  423. mov si,LocalBufferOffset
  424. push ss
  425. pop ds
  426. mov es,cx
  427. int 21h
  428. pop es
  429. pop ds
  430. jnc x
  431. mov OK,0
  432. x:
  433. }
  434. if(OK) {
  435. if(((unsigned)toupper(LocalBuffer[0]) == (Drive + (unsigned)'A' - 1))
  436. && (LocalBuffer[1] == ':')) {
  437. //
  438. // Found it. We're done.
  439. //
  440. return(TRUE);
  441. }
  442. Index++;
  443. }
  444. } while(OK);
  445. //
  446. // Couldn't find it.
  447. //
  448. UncPath[0] = 0;
  449. }
  450. return(TRUE);
  451. } else {
  452. return(FALSE);
  453. }
  454. }
  455. BOOLEAN
  456. DnIsDriveRemovable(
  457. IN unsigned Drive
  458. )
  459. /*++
  460. Routine Description:
  461. Determine whether a drive is removable.
  462. Arguments:
  463. Drive - drive (1=A, 2=B, etc).
  464. Return Value:
  465. TRUE if drive is removable.
  466. FALSE if not removable.
  467. If an error occurs making the determination, the drive is assumed
  468. not removable.
  469. --*/
  470. {
  471. int ax;
  472. union REGS RegIn,RegOut;
  473. //
  474. // Call IOCTL function 08.
  475. //
  476. RegIn.x.ax = 0x4408;
  477. RegIn.h.bl = (unsigned char)Drive;
  478. ax = intdos(&RegIn,&RegOut);
  479. //
  480. // If an error occured, assume not removable.
  481. // If no error, ax = 0 if removable, ax = 1 if not removable.
  482. //
  483. return((BOOLEAN)(!RegOut.x.cflag && !ax));
  484. }
  485. BOOLEAN
  486. DnCanonicalizePath(
  487. IN PCHAR PathIn,
  488. OUT PCHAR PathOut
  489. )
  490. /*++
  491. Routine Description:
  492. Canonicalize a path. The result is a fully-qualified path
  493. that always starts with the x:\ for local or local-redirected
  494. drives, or \\ for remote paths.
  495. Arguments:
  496. PathIn - supplies the path to be canonicalized. The path must be
  497. valid (ie, it must be some form of syntactically correct MS-DOS path
  498. and must actually exist and be accessible) for this function
  499. to succeed.
  500. PathOut - receives the canonicalized path if successful. The function
  501. assumes that the buffer has space for 128 bytes.
  502. Return Value:
  503. Boolean value indicating outcome. If TRUE, PathOut will be filled in.
  504. --*/
  505. {
  506. BOOLEAN OK;
  507. int olddrive;
  508. char olddir[128];
  509. int drive;
  510. //
  511. // If the input path is UNC then we assume
  512. // the path is remote and note that the dos canonicalize
  513. // int21 function will do what we want.
  514. //
  515. if((PathIn[0] == '\\') && (PathIn[1] == '\\')) {
  516. OK = TRUE;
  517. _asm {
  518. push ds
  519. push es
  520. mov si,word ptr [PathIn]
  521. mov ax,word ptr [PathIn+2]
  522. mov di,word ptr [PathOut]
  523. mov cx,word ptr [PathOut+2]
  524. mov ds,ax
  525. mov es,cx
  526. mov ax,0x6000
  527. int 21h
  528. pop es
  529. pop ds
  530. jnc x
  531. mov OK,0
  532. x:
  533. }
  534. } else {
  535. //
  536. // Not UNC. We set and read the cwd to simulate what we want.
  537. // Preserve current cwd if possible.
  538. //
  539. olddrive = _getdrive();
  540. if(!getcwd(olddir,sizeof(olddir))) {
  541. olddir[0] = 0;
  542. }
  543. //
  544. // If we have x: at the front, strip it and set the current drive.
  545. // We do this because chdir does not set the current drive.
  546. //
  547. OK = TRUE;
  548. if(isalpha(PathIn[0]) && (PathIn[1] == ':')) {
  549. if(_chdrive(toupper(PathIn[0]) + 1 - (int)'A')) {
  550. OK = FALSE;
  551. } else {
  552. PathIn += 2;
  553. }
  554. }
  555. if(OK) {
  556. OK = (BOOLEAN)(!chdir(PathIn) && (drive = _getdrive()) && _getdcwd(drive,PathOut,128));
  557. }
  558. if(olddir[0]) {
  559. chdir(olddir);
  560. }
  561. if(olddrive) {
  562. _chdrive(olddrive);
  563. }
  564. }
  565. return(OK);
  566. }
  567. #if DBG
  568. long allocated;
  569. long allocs;
  570. #define MEMSIG 0xa3f8
  571. #define callerinfo() printf(" -- Caller: %s, line %u\n",file,line)
  572. #endif
  573. PVOID
  574. Malloc(
  575. IN unsigned Size,
  576. IN BOOLEAN MustSucceed
  577. #if DBG
  578. ,IN char *file,
  579. IN int line
  580. #endif
  581. )
  582. /*++
  583. Routine Description:
  584. Allocates memory and fatal errors if none is available.
  585. Arguments:
  586. Size - number of bytes to allocate
  587. MustSucceed - if true, then the allocation must succeed. If memory
  588. cannot be allocated to satisfy the request, the program displays
  589. a fatal error message and exits.
  590. Return Value:
  591. Pointer to memory. If MustSucceed is TRUE, DOES NOT RETURN
  592. if memory is not available.
  593. --*/
  594. {
  595. unsigned *p;
  596. #if DBG
  597. p = malloc(Size+(2*sizeof(unsigned)));
  598. if(p) {
  599. *p++ = Size;
  600. *(unsigned *)(((PCHAR)p)+Size) = MEMSIG;
  601. allocated += Size;
  602. allocs++;
  603. } else {
  604. if(MustSucceed) {
  605. DnFatalError(&DnsOutOfMemory);
  606. }
  607. }
  608. #else
  609. if((p = malloc(Size)) == NULL) {
  610. if(MustSucceed) {
  611. DnFatalError(&DnsOutOfMemory);
  612. }
  613. }
  614. #endif
  615. return(p);
  616. }
  617. VOID
  618. Free(
  619. IN PVOID Block
  620. #if DBG
  621. ,IN char *file,
  622. IN int line
  623. #endif
  624. )
  625. /*++
  626. Routine Description:
  627. Free a block of memory previously allocated with Malloc().
  628. Arguments:
  629. Block - supplies pointer to block to free.
  630. Return Value:
  631. None.
  632. --*/
  633. {
  634. #if 0
  635. extern char *CommonStrings[];
  636. int i;
  637. for( i = 0; i < sizeof(CommonStrings)/sizeof(char *); i++ ) {
  638. if( (char *)Block == CommonStrings[i] ) {
  639. return;
  640. }
  641. }
  642. #endif
  643. #if DBG
  644. unsigned *p;
  645. if(!allocs) {
  646. printf("Free: allocation count going negative!\n");
  647. callerinfo();
  648. _asm { int 3 }
  649. }
  650. allocs--;
  651. p = ((unsigned *)Block) - 1;
  652. allocated -= *p;
  653. if(allocated < 0) {
  654. printf("Free: total allocation going negative!\n");
  655. callerinfo();
  656. _asm { int 3 }
  657. }
  658. if(*(unsigned *)((PCHAR)Block+(*p)) != MEMSIG) {
  659. printf("Free: memory block lacks MEMSIG!\n");
  660. callerinfo();
  661. _asm { int 3 }
  662. }
  663. free(p);
  664. #else
  665. free(Block);
  666. #endif
  667. }
  668. PVOID
  669. Realloc(
  670. IN PVOID Block,
  671. IN unsigned Size,
  672. IN BOOLEAN MustSucceed
  673. #if DBG
  674. ,IN char *file,
  675. IN int line
  676. #endif
  677. )
  678. /*++
  679. Routine Description:
  680. Reallocates a block of memory previously allocated with Malloc();
  681. fatal errors if none is available.
  682. Arguments:
  683. Block - supplies pointer to block to resize
  684. Size - number of bytes to allocate
  685. MustSucceed - if true, then the allocation must succeed. If memory
  686. cannot be allocated to satisfy the request, the program displays
  687. a fatal error message and exits.
  688. Return Value:
  689. Pointer to memory. If MustSucceed is TRUE,
  690. DOES NOT RETURN if memory is not available.
  691. --*/
  692. {
  693. PVOID p;
  694. #if DBG
  695. unsigned BlockSize;
  696. BlockSize = ((unsigned *)Block)[-1];
  697. allocated -= BlockSize;
  698. allocated += Size;
  699. if(*(unsigned *)((PCHAR)Block + BlockSize) != MEMSIG) {
  700. printf("Realloc: memory block lacks MEMSIG!\n");
  701. callerinfo();
  702. _asm { int 3 }
  703. }
  704. p = realloc((unsigned *)Block - 1,Size + (2*sizeof(unsigned)));
  705. if(p == NULL) {
  706. if(MustSucceed) {
  707. DnFatalError(&DnsOutOfMemory);
  708. }
  709. } else {
  710. *(unsigned *)p = Size;
  711. (unsigned *)p += 1;
  712. *(unsigned *)((PCHAR)p + Size) = MEMSIG;
  713. }
  714. #else
  715. if((p = realloc(Block,Size)) == NULL) {
  716. if(MustSucceed) {
  717. DnFatalError(&DnsOutOfMemory);
  718. }
  719. }
  720. #endif
  721. return(p);
  722. }
  723. VOID
  724. DnExit(
  725. IN int ExitStatus
  726. )
  727. /*++
  728. Routine Description:
  729. Exits back to DOS in an orderly fashion.
  730. Arguments:
  731. ExitStatus - supplies value to be passed to exit()
  732. Return Value:
  733. None. Does not return.
  734. --*/
  735. {
  736. unsigned DriveCount;
  737. //
  738. // Do a video mode switch to clear the screen.
  739. //
  740. #if NEC_98
  741. _asm {
  742. mov al,5
  743. out 0a2h,al
  744. mov ax,0a00h
  745. int 18h
  746. mov ah,11h // function -- cursor on
  747. int 18h
  748. }
  749. if(ExitStatus != 2){
  750. printf("\x1b[>3l");
  751. printf("\x1b[>1l");
  752. }
  753. else { ExitStatus = 0; }
  754. #else // NEC_98
  755. _asm {
  756. mov ax,3
  757. int 10h
  758. }
  759. #endif // NEC_98
  760. // restore current drive
  761. _dos_setdrive(DngOriginalCurrentDrive,&DriveCount);
  762. exit(ExitStatus);
  763. }
  764. BOOLEAN
  765. DnWriteSmallIniFile(
  766. IN PCHAR Filename,
  767. IN PCHAR *Lines,
  768. OUT FILE **FileHandle OPTIONAL
  769. )
  770. {
  771. FILE *fileHandle;
  772. unsigned i,len;
  773. BOOLEAN rc;
  774. //
  775. // If the file is already there, change attributes to normal
  776. // so we can overwrite it.
  777. //
  778. _dos_setfileattr(Filename,_A_NORMAL);
  779. //
  780. // Open/truncate the file.
  781. //
  782. fileHandle = fopen(Filename,"wt");
  783. if(fileHandle == NULL) {
  784. return(FALSE);
  785. }
  786. //
  787. // Assume success.
  788. //
  789. rc = TRUE;
  790. //
  791. // Write lines into the file indicating that this is
  792. // a winnt setup. On a doublespaced floppy, there should
  793. // be room for a single sector outside the CVF.
  794. //
  795. for(i=0; Lines[i]; i++) {
  796. len = strlen(Lines[i]);
  797. if(fwrite(Lines[i],1,len,fileHandle) != len) {
  798. rc = FALSE;
  799. break;
  800. }
  801. }
  802. //
  803. // Leave the file open if the caller wants the handle.
  804. //
  805. if(rc && FileHandle) {
  806. *FileHandle = fileHandle;
  807. } else {
  808. fclose(fileHandle);
  809. }
  810. return(rc);
  811. }
  812. int
  813. vsnprintf( char* target, size_t bufsize, const char *format, va_list val )
  814. {
  815. static CHAR BigFormatBuffer[4096];
  816. size_t retval;
  817. //
  818. // Print into the big format buffer, which we're sure will be large enough
  819. // to store 99.44% of all strings printed through here.
  820. //
  821. retval = vsprintf( BigFormatBuffer, format, val );
  822. BigFormatBuffer[retval++] = '\0';
  823. //
  824. // And then transfer it over to the output buffer, but only as much as they
  825. // wanted.
  826. //
  827. memcpy( target, BigFormatBuffer, retval < bufsize ? retval : bufsize );
  828. //
  829. // Zero out the end as well.
  830. //
  831. target[bufsize-1] = '\0';
  832. return retval;
  833. }
  834. int
  835. snprintf( char* target, size_t bufsize, const char *format, ... )
  836. {
  837. int retval;
  838. va_list val;
  839. va_start(val, format);
  840. retval = vsnprintf( target, bufsize, format, val );
  841. va_end( val );
  842. return retval;
  843. }