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.

2390 lines
62 KiB

  1. /*
  2. * UP.C
  3. *
  4. * User Profile routines
  5. *
  6. * These are the routines which read and write INI files.
  7. *
  8. * Exported routines:
  9. *
  10. * GetProfileString
  11. * GetPrivateProfileString
  12. * GetProfileInt
  13. * GetPrivateProfileInt
  14. * WriteProfileString
  15. * WritePrivateProfileString
  16. *
  17. * Note the parameter "lpSection" used to be known as "lpApplicationName".
  18. * The code always referred to sections, so the parameter has been changed.
  19. *
  20. * Rewritten 6/90 for C 6.0.
  21. */
  22. #include "kernel.h"
  23. /*
  24. * Required definitions for exported routines:
  25. */
  26. #define API _far _pascal _loadds
  27. HANDLE API IGlobalAlloc(WORD, DWORD);
  28. HANDLE API IGlobalFree(HANDLE);
  29. LPSTR API IGlobalLock(HANDLE);
  30. HANDLE API IGlobalReAlloc(HANDLE, DWORD, WORD);
  31. BOOL API IGlobalUnlock(HANDLE);
  32. /* #pragma optimize("t", off) */
  33. /* This ensures that only one selector is required in PMODE */
  34. #define MAXBUFLEN 0xFFE0L
  35. #define SPACE ' '
  36. #define TAB '\t'
  37. #define LINEFEED '\n'
  38. #define CR '\r'
  39. #define SECT_LEFT '['
  40. #define SECT_RIGHT ']'
  41. #define CTRLZ ('Z'-'@')
  42. /* Constants for WriteProfileString - DON'T CHANGE THESE */
  43. #define NOSECTION 0
  44. #define NOKEY 1
  45. #define NEWRESULT 2
  46. #define REMOVESECTION 3
  47. #define REMOVEKEY 4
  48. /* Flags about a file kept in ProInfo
  49. * If the PROUNCLEAN label is changed, its value must also be
  50. * changed in I21ENTRY.ASM, where it is assumed to be 2.
  51. */
  52. #define PROCOMMENTS 1 /* contains comments */
  53. #define PROUNCLEAN 2 /* has not been written */
  54. #define PROMATCHES 4 /* buffer matches disk copy */
  55. #define PROREADONLY 8 /* Read only file */
  56. #define PRO_CREATED 16 /* File was just created */
  57. /* Sharing violation. */
  58. #define SHARINGVIOLATION 0x0020
  59. /* For forcing variables into the current code segment */
  60. #define CODESEG _based(_segname("_CODE"))
  61. /* Hide disgusting _based syntax */
  62. #define BASED_ON_LP(x) _based((_segment)x)
  63. #define BASED_ON_SEG(x) _based(x)
  64. #define SEGMENT _segment
  65. /* Externals assumed to be in DGROUP */
  66. extern PROINFO WinIniInfo;
  67. extern PROINFO PrivateProInfo;
  68. extern LPSTR lpWindowsDir;
  69. extern int cBytesWinDir;
  70. extern int WinFlags;
  71. extern char fBooting;
  72. extern char fProfileDirty;
  73. extern char fProfileMaybeStale;
  74. extern char fAnnoyEarle;
  75. extern char fBooting;
  76. extern LPSTR curDTA;
  77. extern BYTE fWriteOutProfilesReenter;
  78. /* Forward definitions to keep compiler happy */
  79. /* _fastcall may save some space on internal routines */
  80. LPSTR _fastcall BufferInit(PROINFO *, int);
  81. LPSTR _fastcall LockBuffer(PROINFO *);
  82. void _fastcall UnlockBuffer(PROINFO *);
  83. LPSTR _fastcall FreeBuffer(PROINFO *);
  84. LPSTR _fastcall PackBuffer(PROINFO *, int, int);
  85. void _fastcall FlushDirtyFile(PROINFO *);
  86. int GetInt(PROINFO *, LPSTR, LPSTR, int);
  87. int GetString(PROINFO *, LPSTR, LPSTR, LPSTR, LPSTR, int);
  88. LPSTR FindString(PROINFO *, LPSTR, LPSTR);
  89. LPSTR FindSection(LPSTR, LPSTR);
  90. LPSTR FindKey(LPSTR, LPSTR);
  91. int WriteString(PROINFO *, LPSTR, LPSTR, LPSTR);
  92. void strcmpi(void);
  93. int MyStrlen(void);
  94. void API WriteOutProfiles(void);
  95. PROINFO * SetPrivateProInfo(LPSTR,LPSTR);
  96. int GetSection(PROINFO*, LPSTR, LPSTR, int);
  97. int IsItTheSame(LPSTR, LPSTR);
  98. int Cstrlen(LPSTR);
  99. int MakeRoom(LPSTR, int, int*);
  100. int InsertSection(LPSTR, LPSTR, short);
  101. int InsertKey(LPSTR, LPSTR, short);
  102. int InsertResult(LPSTR, LPSTR, short);
  103. int DeleteSection(LPSTR, PROINFO*);
  104. int DeleteKey(LPSTR, PROINFO*);
  105. /* External KERNEL routines */
  106. void _far _pascal FarMyLower();
  107. int API lstrOriginal(LPSTR,LPSTR); /* lstrcmp in disguise */
  108. #ifdef FE_SB
  109. // Delacred in kernel.h already
  110. // void _far _pascal AnsiPrev(LPSTR,LPSTR);
  111. void _far _pascal FarMyIsDBCSLeadByte();
  112. #endif
  113. char CODESEG WinIniStr[] = "WIN.INI";
  114. /* DOS FindFirst/FindNext structure (43h, 44h) */
  115. typedef struct tagFILEINFO
  116. {
  117. BYTE fiReserved[21];
  118. BYTE fiAttribute;
  119. WORD fiFileTime;
  120. WORD fiFileDate;
  121. DWORD fiSize;
  122. BYTE fiFileName[13];
  123. } FILEINFO;
  124. /*
  125. * Get[Private]ProfileInt
  126. *
  127. * Parameters:
  128. * lpSection Pointer to section to match in INI file
  129. * lpKeyName Pointer to key string to match in file
  130. * nDefault Default value to return if not found
  131. * [lpFile File to use for Private INI]
  132. *
  133. * Returns:
  134. * nDefault section/keyname not found
  135. * number found in file if section/keyname found
  136. */
  137. int API
  138. IGetProfileInt(lpSection, lpKeyName, nDefault)
  139. LPSTR lpSection;
  140. LPSTR lpKeyName;
  141. int nDefault;
  142. {
  143. int nReturn;
  144. /* Make sure we don't try to flush INI files on DOS calls */
  145. ++fWriteOutProfilesReenter;
  146. /* Reread INI file first if necessary */
  147. FlushDirtyFile(&WinIniInfo);
  148. nReturn = GetInt(&WinIniInfo, lpSection, lpKeyName, nDefault);
  149. --fWriteOutProfilesReenter;
  150. return nReturn;
  151. }
  152. int API
  153. IGetPrivateProfileInt(lpSection, lpKeyName, nDefault, lpFile)
  154. LPSTR lpSection;
  155. LPSTR lpKeyName;
  156. int nDefault;
  157. LPSTR lpFile;
  158. {
  159. PROINFO *pProInfo;
  160. char Buffer[128];
  161. int nReturn;
  162. /* Make sure we don't try to flush INI files on DOS calls */
  163. ++fWriteOutProfilesReenter;
  164. pProInfo = SetPrivateProInfo(lpFile, (LPSTR)Buffer);
  165. /* Reread INI file first if necessary */
  166. FlushDirtyFile(pProInfo);
  167. nReturn = GetInt(pProInfo, lpSection, lpKeyName, nDefault);
  168. --fWriteOutProfilesReenter;
  169. return nReturn;
  170. }
  171. /*
  172. * Get[Private]ProfileString
  173. *
  174. * Parameters:
  175. * lpSection Pointer to section to match in INI file
  176. * lpKeyName Pointer to key string to match in file
  177. * lpDefault Default string to return if not found
  178. * lpResult String to fill in
  179. * nSize Max number of characters to copy
  180. * [lpFile] File to use for Private INI
  181. *
  182. * Returns:
  183. * string from file or lpDefault copied to lpResult
  184. * < nSize - 2 Number of characters copied to lpResult
  185. * nSize - 2 lpResult was not big enough
  186. */
  187. int API
  188. IGetProfileString(lpSection, lpKeyName, lpDefault, lpResult, nSize)
  189. LPSTR lpSection;
  190. LPSTR lpKeyName;
  191. LPSTR lpDefault;
  192. LPSTR lpResult;
  193. int nSize;
  194. {
  195. int nReturn;
  196. /* Make sure we don't try to flush INI files on DOS calls */
  197. ++fWriteOutProfilesReenter;
  198. /* Reread INI file first if necessary */
  199. FlushDirtyFile(&WinIniInfo);
  200. nReturn = GetString(&WinIniInfo, lpSection, lpKeyName, lpDefault,
  201. lpResult, nSize);
  202. --fWriteOutProfilesReenter;
  203. return nReturn;
  204. }
  205. int API
  206. IGetPrivateProfileString(lpSection, lpKeyName, lpDefault, lpResult, nSize, lpFile)
  207. LPSTR lpSection;
  208. LPSTR lpKeyName;
  209. LPSTR lpDefault;
  210. LPSTR lpResult;
  211. int nSize;
  212. LPSTR lpFile;
  213. {
  214. PROINFO *pProInfo;
  215. char Buffer[128];
  216. int nReturn;
  217. /* Make sure we don't try to flush INI files on DOS calls */
  218. ++fWriteOutProfilesReenter;
  219. pProInfo = SetPrivateProInfo(lpFile, (LPSTR)Buffer);
  220. /* Reread INI file first if necessary */
  221. FlushDirtyFile(pProInfo);
  222. nReturn = GetString(pProInfo, lpSection, lpKeyName, lpDefault,
  223. lpResult, nSize);
  224. --fWriteOutProfilesReenter;
  225. return nReturn;
  226. }
  227. /*
  228. * Write[Private]ProfileString
  229. *
  230. * Parameters:
  231. * lpSection Pointer to section to match/add to INI file
  232. * lpKeyName Pointer to key string to match/add to file
  233. * lpString String to add to file
  234. * [lpFile] File to use for Private INI
  235. *
  236. * Returns:
  237. * 0 Failed
  238. * 1 Success
  239. */
  240. int API
  241. IWriteProfileString(lpSection, lpKeyName, lpString)
  242. LPSTR lpSection;
  243. LPSTR lpKeyName;
  244. LPSTR lpString;
  245. {
  246. int nReturn;
  247. /* Make sure we don't try to flush INI files on DOS calls */
  248. ++fWriteOutProfilesReenter;
  249. /* Reread INI file first if necessary */
  250. FlushDirtyFile(&WinIniInfo);
  251. nReturn = WriteString(&WinIniInfo, lpSection, lpKeyName, lpString);
  252. --fWriteOutProfilesReenter;
  253. return nReturn;
  254. }
  255. int API
  256. IWritePrivateProfileString(lpSection, lpKeyName, lpString, lpFile)
  257. LPSTR lpSection;
  258. LPSTR lpKeyName;
  259. LPSTR lpString;
  260. LPSTR lpFile;
  261. {
  262. PROINFO *pProInfo;
  263. char Buffer[128];
  264. int nReturn;
  265. /* Make sure we don't try to flush INI files on DOS calls */
  266. ++fWriteOutProfilesReenter;
  267. pProInfo = SetPrivateProInfo(lpFile, (LPSTR)Buffer);
  268. /* Reread INI file first if necessary */
  269. FlushDirtyFile(pProInfo);
  270. nReturn = WriteString(pProInfo, lpSection, lpKeyName, lpString);
  271. --fWriteOutProfilesReenter;
  272. return nReturn;
  273. }
  274. /* FlushDirtyFile
  275. * Rereads a file if it has been "dirtied" by another task. To
  276. * see if the file has been dirtied, we check the time/date
  277. * stamp.
  278. */
  279. void _fastcall FlushDirtyFile(PROINFO *pProInfo)
  280. {
  281. FILEINFO FileInfo;
  282. DWORD dwSaveDTA;
  283. /* We only have to do this if the file COULD have changed and
  284. * that we already have something cached. Also, there's
  285. * no need to do this at boot time because this is a
  286. * safeguard against the USER doing something bad!
  287. */
  288. if (fBooting || !fProfileMaybeStale || !pProInfo->lpBuffer)
  289. return;
  290. /* The OFSTRUCT in the PROINFO buffer should have the most recent
  291. * date and time when the file was opened. We just compare the
  292. * current date and time to this.
  293. */
  294. _asm
  295. {
  296. ;** Save old DTA and point to our structure
  297. mov ah,2fh ;Get DTA. Int21 code calls DOS only
  298. int 21h ; if necessary. DTA in ES:BX
  299. jc RDF_FlushIt ;Problem, so better flush it
  300. mov WORD PTR dwSaveDTA[2],es ;Save for later
  301. mov WORD PTR dwSaveDTA[0],bx
  302. mov ah,1ah ;Set DTA
  303. push ds ;Can't do a SetKernelDS so push/pop
  304. push ss ;Get SS=DS
  305. pop ds
  306. lea dx,FileInfo ;Point DTA to our structure
  307. int 21h ;Set the DTA
  308. pop ds
  309. jc RDF_FlushIt ;Problem, so just flush it
  310. ;** Do a FindFirst on the file to get date and time reliably
  311. xor cx,cx ;Normal file
  312. mov si,pProInfo ;Point to pathname with DS:DX
  313. lea dx,[si].ProBuf
  314. add dx,8 ;(offset of szPathName)
  315. mov ah,4eh ;Find first
  316. int 21h ;Call DOS
  317. jc RDF_FlushIt ;Can't find, so better flush it
  318. ;** Put DTA back
  319. push ds
  320. lds dx,dwSaveDTA ;DS:DX points to old DTA
  321. mov ah,1ah
  322. int 21h
  323. pop ds
  324. ;** Compare the date and time
  325. lea bx,FileInfo ;Point to FILEINFO
  326. mov dx,ss:[bx + 24] ;Date in FILEINFO structure
  327. mov cx,ss:[bx + 22] ;Tile in FILEINFO structure
  328. mov si,pProInfo ;Point to OFSTRUCT with DS:SI
  329. lea si,[si].ProBuf
  330. cmp [si + 4],dx ;Same date as original?
  331. jne RDF_FlushIt ;No
  332. cmp [si + 6],cx ;Same time as original?
  333. je RDF_NoFlush ;No
  334. }
  335. /* Force a file reread */
  336. RDF_FlushIt:
  337. FreeBuffer(pProInfo);
  338. RDF_NoFlush:
  339. /* Clear the dirty flag */
  340. fProfileMaybeStale = 0;
  341. }
  342. /*
  343. * SetPrivateProInfo
  344. *
  345. * Force a private profile into the windows directory if necessary.
  346. * Check if it is the same file as is currently cached.
  347. * If not, discard the cached file.
  348. * Sets up the PrivateProInfo data structure.
  349. *
  350. * Parameters:
  351. * lpFile Pointer to filename to be used as a profile
  352. * Buffer Buffer to parse filename into
  353. *
  354. * Returns:
  355. * PROINFO * Pointer to information about ini file
  356. */
  357. PROINFO *
  358. SetPrivateProInfo(lpFile, Buffer)
  359. LPSTR lpFile;
  360. LPSTR Buffer;
  361. {
  362. OFSTRUCT NewFileBuf;
  363. char c;
  364. char fQualified = 0;
  365. char BASED_ON_LP(lpFile) *psrc;
  366. int Count = 0;
  367. /* Get rid of annoying warnings with this ugly cast */
  368. psrc = (char BASED_ON_LP(lpFile)*)(WORD)(DWORD)lpFile;
  369. /* For those who insist on using private routines for WIN.INI */
  370. if ( lstrOriginal(lpFile, (LPSTR)WinIniStr) == 0
  371. || lstrOriginal(lpFile, WinIniInfo.ProBuf.szPathName) == 0 ) {
  372. return(&WinIniInfo);
  373. }
  374. /*
  375. * Following code is from ForcePrivatePro
  376. *
  377. * If the filename given is not qualified, we force
  378. * it into the windows directory.
  379. */
  380. #ifdef FE_SB
  381. _asm {
  382. ;Apr.26,1990 by AkiraK
  383. cld
  384. push ds ;save kernel DS
  385. xor ax,ax
  386. mov bx,'/' shl 8 + '\\' ; '/' or '\'
  387. xor dx,dx
  388. lds si,lpFile ; first get length of string
  389. mov cx,si
  390. mov al,ds:[si]
  391. call FarMyIsDBCSLeadByte
  392. jnc fpp_s1
  393. cmp byte ptr ds:[si+1],':' ;
  394. jnz fpp_s1
  395. inc dx
  396. fpp_s1:
  397. fpp_l1:
  398. lodsb
  399. or al,al
  400. jz fpp_got_length
  401. cmp al,bh
  402. jz fpp_qualified
  403. cmp al,bl
  404. jz fpp_qualified
  405. fpp_s2:
  406. call FarMyIsDBCSLeadByte
  407. jc fpp_l1
  408. inc si
  409. jmp fpp_l1
  410. fpp_qualified:
  411. inc dx
  412. jmp fpp_s2
  413. fpp_got_length:
  414. ;; mov fQualified, dx
  415. mov fQualified, dl ; a byte variable
  416. sub si, cx
  417. mov Count, si
  418. pop ds ;recover kernel DS
  419. }
  420. #else
  421. /* Drive specified? */
  422. if ( *(psrc+1) == ':' )
  423. fQualified++;
  424. while ( c = *psrc++ ) {
  425. /* Look for path separators */
  426. if ( c == '/' || c == '\\' )
  427. fQualified++;
  428. Count++;
  429. }
  430. #endif
  431. /*
  432. * Now copy filename to buffer.
  433. * Prepend Windows directory if not qualified.
  434. */
  435. _asm {
  436. cld
  437. push ds
  438. les di, Buffer ; Destination is Buffer
  439. cmp fQualified, 0
  440. jnz Qualified
  441. mov cx, cBytesWinDir ; Pick up Windows directory
  442. lds si, lpWindowsDir
  443. rep movsb ; Copy it
  444. mov al, '\\'
  445. cmp es:[di-1], al ; BUG FIX: if in root, don't
  446. je Qualified ; add separator
  447. stosb ; Add path separator
  448. Qualified:
  449. lds si, lpFile ; Now add Filename we were given
  450. mov cx, Count
  451. inc cx ; Allow for NULL
  452. rep movsb
  453. pop ds
  454. }
  455. #ifdef NOTNOW
  456. if ( !fBooting && fQualified ) {
  457. /*
  458. * Use OpenFile to generate pathname for
  459. * comparison with the cached pathname.
  460. * OF_EXIST ensures we get a complete pathname
  461. * We cannot use OF_PARSE, it does not search the path.
  462. * We only do this if the pathname we were given was
  463. * qualified since in other cases we force the file
  464. * into the windows directory and therefore know
  465. * that Buffer contains the complete pathname.
  466. */
  467. NewFileBuf.szPathName[0] = 0;
  468. OpenFile(Buffer, &NewFileBuf, OF_EXIST);
  469. }
  470. #endif
  471. /* Now see if the filename matches the cached filename */
  472. _asm {
  473. cld
  474. xor cx, cx
  475. lea si, word ptr [PrivateProInfo.ProBuf] ; Cached INI OFSTRUCT
  476. mov cl, [si].cBytes
  477. lea si, word ptr [si].szPathName ; Cached filename
  478. sub cx, 8 ; Get its length
  479. UseOriginal: ; Use the filename they gave us
  480. les di, Buffer ; while booting
  481. xor bl, bl
  482. call strcmpi ; Ignore case while booting
  483. jmp short DoWeDiscardIt
  484. JustCompare:
  485. ; Not booting, compare OFSTRUCTS
  486. ; Note OpenFile forced upper case
  487. push ss
  488. pop es ; NewFileBuf is on SS
  489. lea di, word ptr NewFileBuf.szPathName[0];
  490. rep cmpsb ; Compare filenames
  491. DoWeDiscardIt:
  492. jz WeHaveItCached ; Don't discard if names match
  493. }
  494. /*
  495. * The cached file is not the right one,
  496. * so we discard the saved file.
  497. */
  498. FreeBuffer(&PrivateProInfo);
  499. WeHaveItCached:
  500. /* Save pointer to FileName - buffer may have been discarded */
  501. PrivateProInfo.lpProFile = Buffer;
  502. return(&PrivateProInfo);
  503. }
  504. /*
  505. * GetInt - search file and return an integer
  506. *
  507. * Parameters:
  508. * pProInfo Pointer to information on the INI file
  509. * lpSection Pointer to section to match in INI file
  510. * lpKeyName Pointer to key string to match in file
  511. * nDefault Default value to return if not found
  512. *
  513. * Returns:
  514. * see GetProfileInt
  515. */
  516. int
  517. GetInt(pProInfo, lpSection, lpKeyName, nDefault)
  518. PROINFO *pProInfo;
  519. LPSTR lpSection;
  520. LPSTR lpKeyName;
  521. int nDefault;
  522. {
  523. LPSTR lpResult;
  524. lpResult = FindString(pProInfo, lpSection, lpKeyName);
  525. if (lpResult) {
  526. /* We found a string, convert to int */
  527. register int c;
  528. int radix = 10;
  529. BOOL fNeg = FALSE;
  530. // Skip spaces
  531. while (*lpResult == ' ' || *lpResult == '\t')
  532. ++lpResult;
  533. nDefault = 0;
  534. while ((c = *lpResult++) != 0) {
  535. // Watch for change in sign
  536. //
  537. if (c == '-') {
  538. fNeg = !fNeg;
  539. continue;
  540. }
  541. // Lower case the character if it's a letter.
  542. //
  543. if (c >= 'A' && c <= 'Z')
  544. c += ('a' - 'A');
  545. // deal with hex constants
  546. //
  547. if (c == 'x') {
  548. radix = 16;
  549. continue;
  550. }
  551. c -= '0';
  552. if (c > 9)
  553. c += '0' - 'a' + 10;
  554. if (c < 0 || c >= radix)
  555. break;
  556. nDefault = nDefault * radix + c;
  557. }
  558. if (fNeg)
  559. nDefault = -nDefault;
  560. }
  561. UnlockBuffer(pProInfo);
  562. return(nDefault);
  563. }
  564. /*
  565. * GetString - Search file for a specific Section and KeyName
  566. *
  567. * Parameters:
  568. * pProInfo Pointer to information on the INI file
  569. * lpSection Pointer to section to match in INI file
  570. * lpKeyName Pointer to key string to match in file
  571. * lpDefault Default string to return if not found
  572. * lpResult String to fill in
  573. * nSize Max number of characters to copy
  574. *
  575. * Returns:
  576. * see GetProfileString
  577. */
  578. GetString(pProInfo, lpSection, lpKeyName, lpDefault, lpResult, nSize)
  579. PROINFO *pProInfo;
  580. LPSTR lpSection;
  581. LPSTR lpKeyName;
  582. LPSTR lpDefault;
  583. LPSTR lpResult;
  584. int nSize;
  585. {
  586. int nFound;
  587. LPSTR lpFound;
  588. if ( !lpKeyName ) {
  589. nFound = GetSection(pProInfo, lpSection, lpResult, nSize);
  590. if ( nFound == -1 )
  591. goto CopyDefault; /* Yes, I know! */
  592. } else {
  593. lpFound = FindString(pProInfo, lpSection, lpKeyName);
  594. if ( lpFound )
  595. lpDefault = lpFound;
  596. CopyDefault:
  597. _asm {
  598. xor ax, ax ; Return value
  599. cmp word ptr lpDefault[2], 0 ; Check for null default
  600. je SavedMe
  601. les di, lpDefault
  602. call MyStrlen ; Returns length in CX
  603. ; Fix for #10907 -- Used to GP fault on zero length str.
  604. or cx,cx ; No characters in string?
  605. je strdone
  606. #ifdef FE_SB
  607. ; Get last character behind terminator
  608. push si
  609. les si, lpDefault ; SI = front of string
  610. gps_dbcs_l1:
  611. mov al, es:[si]
  612. call FarMyIsDBCSLeadByte
  613. cmc
  614. adc si, 1
  615. cmp si, di
  616. jb gps_dbcs_l1
  617. pop si
  618. #else
  619. add di, cx
  620. mov al, es:[di-1] ; Final character in string
  621. #endif
  622. les di, lpDefault
  623. cmp cx, 2 ; strlen > 2
  624. jb strdone
  625. ; Strip off single and double quotes
  626. mov ah, es:[di]
  627. cmp ah, al ; First character == last character?
  628. jne strdone
  629. cmp al, '\''
  630. je strq
  631. cmp al, '"'
  632. jne strdone
  633. strq:
  634. sub cx, 2 ; Lose those quotes
  635. inc di
  636. strdone:
  637. ; CX has length of string
  638. mov dx, nSize
  639. dec dx ; Allow for null
  640. cmp cx, dx ; See if enough room
  641. jbe HaveRoom
  642. mov cx, dx
  643. HaveRoom:
  644. cld
  645. push ds
  646. push es
  647. pop ds
  648. mov si, di ; DS:SI has string to return
  649. les di, lpResult
  650. mov ax, cx ; Save length of string
  651. rep movsb ; Copy the string
  652. mov byte ptr es:[di], 0 ; Null terminate the string
  653. pop ds
  654. SavedMe:
  655. mov nFound, ax ; We will return this
  656. }
  657. }
  658. UnlockBuffer(pProInfo);
  659. return(nFound);
  660. }
  661. /*
  662. * GetSection - find a section and copy all KeyNames to lpResult
  663. *
  664. * Parameters:
  665. * pProInfo pointer to info on the file
  666. * lpSection pointer to the section name we want
  667. * lpResult where the KeyNames will go
  668. * nSize size of lpResult buffer
  669. *
  670. * Returns:
  671. * int Number of characters copied, -1 for failure
  672. */
  673. int
  674. GetSection(pProInfo, lpSection, lpResult, nSize)
  675. PROINFO *pProInfo;
  676. LPSTR lpSection;
  677. LPSTR lpResult;
  678. int nSize;
  679. {
  680. LPSTR lp;
  681. lp = BufferInit(pProInfo, READ);
  682. if ( !lp )
  683. return(-1); /* No buffer, (no file, no memory etc.) */
  684. nSize--; /* Room for terminating NULL */
  685. lp = FindSection(lp, lpSection);
  686. if ( !lp )
  687. return(-1);
  688. _asm {
  689. push ds
  690. lds si, lpResult ; DS:SI is where we store the result
  691. les di, lp ; ES:DI points to the section in buffer
  692. xor dx, dx ; Count of characters in the result
  693. KeyNameLoop:
  694. mov bx, di ; Save start of line
  695. cmp es:[di], ';' ; Is this a comment line?
  696. jne KeyNameNextCh ; no, check this line out
  697. cld
  698. mov cx, -1
  699. mov al, LINEFEED
  700. repne scasb ; Skip to end of the line
  701. jmp KeyNameLoop
  702. KeyNameNextCh:
  703. mov al, es:[di] ; Get next character
  704. #ifdef FE_SB
  705. call FarMyIsDBCSLeadByte
  706. cmc ; if the char is lead byte of DBCS,
  707. adc di, 1 ; then di += 2, else di += 1
  708. #else
  709. inc di
  710. #endif
  711. cmp al, '='
  712. je FoundEquals
  713. cmp al, LINEFEED
  714. je KeyNameLoop ; Ignore lines without an '='
  715. cmp al, SECT_LEFT
  716. je EndSection ; Done if end of section
  717. or al, al ; or if end of buffer (NULL)
  718. jne KeyNameNextCh ; On to the next character
  719. jmp EndSection
  720. FoundEquals:
  721. mov di, bx ; Back to the start of the line
  722. CopyLoop:
  723. mov al, es:[di] ; Pick up next character in line
  724. inc di
  725. cmp al, '=' ; Is it the '='?
  726. jne LeaveItAlone
  727. xor al, al ; yes, replace with NULL
  728. LeaveItAlone:
  729. mov [si], al ; Put it in the result string
  730. inc dx ; Number of characters in the result
  731. inc si
  732. cmp dx, nSize ; Overflowed?
  733. jb NoProblem
  734. dec dx ; yes, ignore this character
  735. dec si
  736. NoProblem:
  737. #ifdef FE_SB
  738. call FarMyIsDBCSLeadByte
  739. jc NoProblem1
  740. mov al, es:[di]
  741. inc di
  742. mov [si], al
  743. inc dx
  744. inc si
  745. cmp dx, nSize
  746. jb NoProblem1
  747. dec si
  748. dec dx
  749. NoProblem1:
  750. #endif
  751. or al, al ; Was this the '='
  752. jne CopyLoop
  753. SkipLine:
  754. mov al, es:[di] ; Skip the rest of the line
  755. inc di
  756. cmp al, LINEFEED
  757. jne SkipLine
  758. jmp KeyNameLoop
  759. EndSection:
  760. mov byte ptr [si], 0 ; Terminate with NULL
  761. or dx, dx ; Did we copy anything?
  762. jz NothingFound ; no, no hack
  763. #ifdef FE_SB
  764. ;AnsiPrev API has been moved to USER and it is not the
  765. ;right time to invoke any USER's APIs as we might be called
  766. ;while USER is still on the bed.
  767. ; push dx
  768. ; push word ptr lpResult[2]
  769. ; push word ptr lpResult[0]
  770. ; push ds
  771. ; push si
  772. ; call AnsiPrev
  773. ; mov si, ax
  774. ; mov byte ptr [si], 0
  775. ; mov byte ptr [si+1], 0
  776. ; pop dx
  777. ;-----------------------------------------------------------
  778. push es
  779. push di
  780. push bx
  781. les di,lpResult ;string head
  782. ScanLoop:
  783. mov bx,di ;"prev" char position
  784. mov al,es:[di]
  785. call FarMyIsDBCSLeadByte
  786. cmc
  787. adc di, 1 ;+2 if DBCS, +1 if not
  788. cmp di,si ;have we hit the point yet?
  789. jb ScanLoop ;nope,
  790. ;The output of this routine looks like:
  791. ;<name 1>,0,<name2>,0,.... <name n>,0,0
  792. ; the very last 0 tells the end of story.
  793. mov es:[bx],0 ;this is safe
  794. mov es:[bx+1],0 ;Hmmmmm
  795. pop bx
  796. pop di
  797. pop es
  798. #else
  799. mov byte ptr [si-1], 0 ; Hack - if we hit nSize, we
  800. #endif
  801. ; and extra NULL
  802. NothingFound:
  803. pop ds
  804. mov nSize, dx
  805. }
  806. return(nSize);
  807. }
  808. /*
  809. * FindString - look for section name and key name
  810. *
  811. * Parameters:
  812. * pProInfo Pointer to info on the file
  813. * lp Pointer to the buffer containing the file
  814. * lpSection Pointer to the section name we are looking for
  815. * lpKeyName Pointer the the KeyName we want
  816. *
  817. * Returns:
  818. * LPSTR Pointer to the start of the result string
  819. * NULL for failure
  820. */
  821. LPSTR
  822. FindString(pProInfo, lpSection, lpKeyName)
  823. PROINFO *pProInfo;
  824. LPSTR lpSection;
  825. LPSTR lpKeyName;
  826. {
  827. LPSTR lp;
  828. if ( lp = BufferInit(pProInfo, READ) )
  829. if ( lp = FindSection(lp, lpSection) )
  830. lp = FindKey(lp, lpKeyName);
  831. return(lp);
  832. }
  833. /*
  834. * FindSection - look for a section name enclosed in '[' and ']'
  835. *
  836. * Parameters:
  837. * lp Pointer to the buffer containing the file
  838. * lpSection Pointer to the section name we are looking for
  839. *
  840. * Returns:
  841. * LPSTR Pointer to the start of the section for success
  842. * NULL for failure
  843. */
  844. LPSTR
  845. FindSection(lp, lpSection)
  846. LPSTR lp;
  847. LPSTR lpSection;
  848. {
  849. WORD wCount;
  850. WORD wTrailCount;
  851. WORD fLead;
  852. LPSTR lpstr;
  853. WORD wSegLen;
  854. /* Remove leading whitespace from section names and compute
  855. * a length count that doesn't include trailing whitespace.
  856. * We use this below to force a TRUE compare even though
  857. * the program put garbage on the end.
  858. */
  859. for (lpstr = lpSection, fLead = 1, wCount = wTrailCount = 0 ;
  860. *lpstr ; ++lpstr)
  861. {
  862. /* If we haven't passed leading space yet... */
  863. if (fLead)
  864. {
  865. if (*lpstr == SPACE || *lpstr == TAB)
  866. ++lpSection;
  867. else
  868. {
  869. fLead = 0;
  870. ++wCount;
  871. ++wTrailCount;
  872. }
  873. }
  874. /* Otherwise this might be trailing space... */
  875. else
  876. {
  877. /* wCount always has correct count, wTrailCount
  878. * never counts whitespace until another
  879. * character is encountered. This allows
  880. * a count of characters excluding trailing
  881. * whitespace.
  882. */
  883. ++wCount;
  884. if (*lpstr != SPACE && *lpstr != TAB)
  885. wTrailCount = wCount;
  886. }
  887. }
  888. wCount = wTrailCount;
  889. _asm {
  890. lsl cx,WORD PTR lp[2] ; Get max possible search len
  891. mov wSegLen,cx ; Save for quick access later
  892. push ds
  893. les di, lp
  894. SectionLoop:
  895. cmp byte ptr es:[di], SECT_LEFT ; ie '['
  896. jne NotThisLine
  897. inc di ; Skip the '['
  898. ;** Check the length of the string
  899. push di ; Save because we're going to trash
  900. mov cx,wSegLen ; Get segment length
  901. sub cx,di ; Subtract off the distance into seg
  902. mov dx,cx ; Save in DX
  903. mov al,SECT_RIGHT ; Stop when we encouter this
  904. #ifdef FE_SB
  905. ;SECT_RIGHT is a legal DBCS second byte
  906. ;and we have to emulate DBCS "repne scasb" here.
  907. fsScanSectRight:
  908. dec cx ;
  909. jz fsScanFinish ; reach to end of segment
  910. scasb ;
  911. je fsScanFinish ; find it!
  912. call FarMyIsDBCSLeadByte
  913. jc fsScanSectRight
  914. inc di ; skip DBCS 2nd byte
  915. dec cx
  916. jnz short fsScanSectRight
  917. fsScanFinish:
  918. #else
  919. repne scasb ; Compare until we find it
  920. #endif
  921. sub dx,cx ; Get true string len
  922. dec dx
  923. pop di
  924. cmp dx,wCount ; Same length?
  925. jne NotThisLine
  926. ;** Now compare the strings. Note that strcmpi returns a
  927. ;** pointer just past the failed char
  928. lds si, lpSection
  929. mov bl, SECT_RIGHT ; Compare up to '['
  930. call strcmpi
  931. je HereItIs
  932. ;** Even if we failed, it might match less trailing whitespace
  933. sub ax,di ; Get length at first mismatch
  934. cmp ax,wCount ; Make sure we mismatched at end
  935. jne NotThisLine ; We didn't so get out
  936. add di,ax ; Bump pointers to end
  937. add si,ax
  938. mov al,es:[di - 1] ; Compare last chars
  939. cmp al,ds:[si - 1] ; Do they match?
  940. jne NotThisLine ; Yes
  941. HereItIs:
  942. mov al, LINEFEED ; Skip the rest of the line
  943. mov cx, -1
  944. repne scasb ; Scans ES:[DI]
  945. mov ax, di
  946. mov dx, es ; Return pointer to section
  947. jmp FoundIt
  948. NotThisLine:
  949. mov al, LINEFEED ; Skip the rest of the line
  950. mov cx, -1 ; Scans ES:[DI]
  951. repne scasb
  952. cmp byte ptr es:[di], 0 ; End of the file?
  953. jne SectionLoop ; nope, continue
  954. xor ax, ax
  955. xor dx, dx ; Return 0
  956. FoundIt:
  957. pop ds
  958. }
  959. }
  960. /*
  961. * FindKey - Find a KeyName given a pointer to the start of a section
  962. *
  963. * Parameters:
  964. * lp Pointer to start of a section
  965. * lpKeyName Pointer the the KeyName we want
  966. *
  967. * Returns:
  968. * LPSTR Pointer to the string following the KeyName
  969. * NULL if KeyName not found
  970. */
  971. LPSTR
  972. FindKey(lp, lpKeyName)
  973. LPSTR lp;
  974. LPSTR lpKeyName;
  975. {
  976. WORD wCount;
  977. WORD wTrailCount;
  978. WORD fLead;
  979. LPSTR lpstr;
  980. WORD wSegLen;
  981. /* Remove leading whitespace from key names and compute
  982. * a length count that doesn't include trailing whitespace.
  983. * We use this below to force a TRUE compare even though
  984. * the program put garbage on the end.
  985. */
  986. for (lpstr = lpKeyName, fLead = 1, wCount = wTrailCount = 0 ;
  987. *lpstr ; ++lpstr)
  988. {
  989. /* If we haven't passed leading space yet... */
  990. if (fLead)
  991. {
  992. if (*lpstr == SPACE || *lpstr == TAB)
  993. ++lpKeyName;
  994. else
  995. {
  996. fLead = 0;
  997. ++wCount;
  998. ++wTrailCount;
  999. }
  1000. }
  1001. /* Otherwise this might be trailing space... */
  1002. else
  1003. {
  1004. /* wCount always has correct count, wTrailCount
  1005. * never counts whitespace until another
  1006. * character is encountered. This allows
  1007. * a count of characters excluding trailing
  1008. * whitespace.
  1009. */
  1010. ++wCount;
  1011. if (*lpstr != SPACE && *lpstr != TAB)
  1012. wTrailCount = wCount;
  1013. }
  1014. }
  1015. wCount = wTrailCount;
  1016. _asm {
  1017. push ds
  1018. mov ax, word ptr lpKeyName
  1019. or ax, word ptr lpKeyName[2]
  1020. jz NoMatch ; Return zero if lpKeyName is 0
  1021. lsl cx,WORD PTR lp[2] ; Get max possible search len
  1022. mov wSegLen,cx ; Save for quick access later
  1023. les di, lp
  1024. ;** See if we're at the end of the section
  1025. FindKeyNext:
  1026. mov al,es:[di] ; Get next character
  1027. or al,al
  1028. jz NoMatch ; End of the file
  1029. cmp al,SECT_LEFT
  1030. je NoMatch ; End of the section
  1031. cmp al,CR ; Blank line?
  1032. je NotThisKey ; Yes, skip this one
  1033. ;** Check the length of the string
  1034. push di ; Save because we're going to trash
  1035. mov cx,wSegLen ; Get segment length
  1036. sub cx,di ; Subtract off the distance into seg
  1037. mov dx,cx ; Save in DX
  1038. mov al,'=' ; Stop when we encouter this
  1039. repne scasb ; Compare until we find it
  1040. sub dx,cx ; Get true string len
  1041. dec dx
  1042. pop di
  1043. cmp dx,wCount ; Same length?
  1044. jne NotThisKey
  1045. ;** Now compare the strings. Note that strcmpi returns a
  1046. ;** pointer just past the failed char.
  1047. mov bl,'=' ; Compare until we hit this
  1048. lds si,lpKeyName
  1049. call strcmpi
  1050. mov bx,di ; Save DI value for below
  1051. mov di,ax
  1052. je FoundKey
  1053. ;** Even if we failed, it might match less trailing whitespace
  1054. sub ax,bx ; Get length at first mismatch
  1055. cmp ax,wCount ; Make sure we mismatched at end
  1056. jne NotThisKey ; Lengths at mismatch must match
  1057. add bx,ax ; Bump pointers to end
  1058. add si,ax
  1059. mov al,es:[bx - 1] ; Get last char that should match
  1060. cmp al,ds:[si - 1] ; Does it match?
  1061. je FoundKey ; Yes
  1062. NotThisKey:
  1063. mov al, LINEFEED
  1064. mov cx, -1
  1065. repne scasb ; Scan to the end of the line
  1066. jmp FindKeyNext
  1067. NoMatch:
  1068. xor ax, ax
  1069. xor dx, dx
  1070. jmp AndReturn
  1071. FoundKey:
  1072. inc di ; Skip the '='
  1073. mov ax, di ; Return the pointer
  1074. mov dx, es
  1075. AndReturn:
  1076. pop ds
  1077. }
  1078. }
  1079. /*
  1080. * MyStrlen - returns length of a string excluding trailing spaces and CR
  1081. *
  1082. * Paremeters:
  1083. * ES:DI pointer to string
  1084. *
  1085. * Returns:
  1086. * CX number of characters in string
  1087. *
  1088. */
  1089. int
  1090. MyStrlen()
  1091. {
  1092. _asm {
  1093. ; SPACE, CR, NULL never in DBCS lead byte, so we are safe here
  1094. push ax
  1095. mov cx, di ; CX = start of string
  1096. dec di
  1097. str1:
  1098. inc di
  1099. mov al, es:[di] ; Get next character
  1100. cmp al, CR
  1101. ja str1 ; Not CR or NULL
  1102. str2:
  1103. cmp di, cx ; Back at the start?
  1104. jbe str3 ; yes
  1105. dec di ; Previous character
  1106. cmp byte ptr es:[di], SPACE
  1107. je str2 ; skip spaces
  1108. inc di ; Back to CR or NULL
  1109. str3:
  1110. cmp es:[di], al
  1111. je maybe_in_code ; PMODE hack
  1112. mov es:[di], al ; Zap trailing spaces
  1113. maybe_in_code:
  1114. neg cx ; Calculate length
  1115. add cx, di
  1116. pop ax
  1117. }
  1118. }
  1119. /*
  1120. * Cstrlen - returns length of a string excluding trailing spaces and CR
  1121. * This is a C callable interface to MyStrLen
  1122. *
  1123. * Paremeters:
  1124. * lp pointer to string
  1125. *
  1126. * Returns:
  1127. * number of characters in string
  1128. *
  1129. */
  1130. int
  1131. Cstrlen(lp)
  1132. LPSTR lp;
  1133. {
  1134. _asm {
  1135. xor di, di ; Persuade compiler to save DI
  1136. les di, lp
  1137. call MyStrlen
  1138. mov ax, cx
  1139. }
  1140. }
  1141. /*
  1142. * strcmpi - internal case insensitive string compare
  1143. *
  1144. * Parameters:
  1145. * ES:DI & DS:SI Strings to be compared
  1146. * BL Character to terminate on
  1147. * DS:SI is null terminated
  1148. *
  1149. * Returns:
  1150. * ZF indicates strings equal
  1151. * AX pointer to next character in ES:DI string
  1152. * or failed character in case of mismatch
  1153. */
  1154. void
  1155. strcmpi()
  1156. {
  1157. _asm {
  1158. #ifdef FE_SB
  1159. ;Apr.26,1990 by AkiraK
  1160. ; Copied directly from USERPRO.ASM
  1161. sti_l1:
  1162. mov al,es:[di]
  1163. cmp al,bl
  1164. jz sti_s1
  1165. call FarMyLower
  1166. mov cl,al
  1167. mov al,ds:[si]
  1168. call FarMyLower
  1169. inc si
  1170. inc di
  1171. cmp al,cl
  1172. jnz sti_exit
  1173. call FarMyIsDBCSLeadByte
  1174. jc sti_l1
  1175. mov al,es:[di]
  1176. cmp al,ds:[si]
  1177. jnz sti_exit
  1178. inc si
  1179. inc di
  1180. jmp short sti_l1
  1181. sti_s1:
  1182. mov al,ds:[si]
  1183. or al,al
  1184. sti_exit:
  1185. mov ax, di
  1186. #else
  1187. stci10:
  1188. mov al,es:[di] ; Get next character
  1189. cmp al,bl ; Character to terminate on?
  1190. jnz stci15 ; no, compare it
  1191. mov al,[si] ; yes, strings equal if at end
  1192. or al,al
  1193. jmp stciex
  1194. stci15:
  1195. call FarMyLower ; Ensure both characters lower case
  1196. mov cl,[si]
  1197. xchg al,cl
  1198. call FarMyLower
  1199. inc si
  1200. inc di
  1201. cmp al,cl ; Still matching chars?
  1202. jz stci10 ; Yes, go try the next char.
  1203. stciex:
  1204. mov ax,di ; Return pointer to next character
  1205. #endif
  1206. }
  1207. }
  1208. /*
  1209. * BufferInit
  1210. *
  1211. * Parameters:
  1212. * pProInfo Pointer to structure describing an INI file
  1213. * OpenFlags READ_WRITE if we are writing to the file
  1214. *
  1215. * Returns:
  1216. * Pointer to start of buffer on success
  1217. * (LPSTR)0 Failure
  1218. *
  1219. * Open or create the INI file as necessary
  1220. * Get a buffer in memory for the file
  1221. * Read the INI file into the buffer
  1222. * Strip unwanted spaces comments and ^Zs from the buffer
  1223. */
  1224. LPSTR _fastcall
  1225. BufferInit(pProInfo, OpenFlags)
  1226. PROINFO *pProInfo;
  1227. int OpenFlags;
  1228. {
  1229. LPSTR BufAddr;
  1230. long llen;
  1231. unsigned short len;
  1232. int fh;
  1233. int hNew;
  1234. BYTE byLastDrive; /* Cache last drive read from */
  1235. /* Ensure we have a handle for the buffer */
  1236. if ( pProInfo->hBuffer == 0 )
  1237. return(0L);
  1238. /* If the buffer is already filled, return */
  1239. if ( (BufAddr = LockBuffer(pProInfo)) != (LPSTR)NULL )
  1240. return(BufAddr);
  1241. pProInfo->ProFlags = 0;
  1242. /* Remember the last drive read from to see if we have to reread
  1243. * the cluster size.
  1244. */
  1245. byLastDrive = *pProInfo->ProBuf.szPathName;
  1246. if ( pProInfo == &PrivateProInfo ) {
  1247. /* Open a PRIVATE profile */
  1248. fh = OpenFile(pProInfo->lpProFile, &pProInfo->ProBuf, READ_WRITE+OF_SHARE_DENY_WRITE);
  1249. if ( fh == -1 ) {
  1250. /* Attempt to open for read. */
  1251. if ( !OpenFlags ){
  1252. pProInfo->ProFlags |= PROREADONLY;
  1253. fh = OpenFile(pProInfo->lpProFile, &pProInfo->ProBuf, READ+OF_SHARE_DENY_WRITE);
  1254. /* If this fails, try compatibility mode. */
  1255. if ( (fh == -1) && (pProInfo->ProBuf.nErrCode == SHARINGVIOLATION) ){
  1256. fh = OpenFile(pProInfo->lpProFile, &pProInfo->ProBuf, READ);
  1257. }
  1258. }else{
  1259. /* If the open failed and we are writing, silently create the file.
  1260. * If the open failed because of sharing violation, try compatibility mode instead.
  1261. */
  1262. if ( pProInfo->ProBuf.nErrCode != SHARINGVIOLATION ){
  1263. OpenFlags |= OF_CREATE;
  1264. }
  1265. fh = OpenFile(pProInfo->lpProFile, &pProInfo->ProBuf, OpenFlags);
  1266. }
  1267. }
  1268. } else {
  1269. /* Open WIN.INI */
  1270. if ( OpenFlags )
  1271. OpenFlags |= OF_CREATE;
  1272. if ( pProInfo->ProBuf.cBytes ) {
  1273. /* If previously found, reopen, don't create */
  1274. OpenFlags |= OF_REOPEN+OF_PROMPT|OF_CANCEL|OF_SHARE_DENY_WRITE;
  1275. OpenFlags &= ~OF_CREATE;
  1276. }
  1277. fh = OpenFile(pProInfo->lpProFile, &pProInfo->ProBuf, OpenFlags|READ_WRITE);
  1278. if ( (fh == -1) && !(OpenFlags & (READ_WRITE|OF_CREATE)) ) {
  1279. pProInfo->ProFlags |= PROREADONLY;
  1280. fh = OpenFile(pProInfo->lpProFile, &pProInfo->ProBuf, OpenFlags+OF_SHARE_DENY_WRITE);
  1281. }
  1282. /* Sharing violation. Let's try compatibility mode. */
  1283. if ( (fh == -1) && ( pProInfo->ProBuf.nErrCode == SHARINGVIOLATION ) ){
  1284. OpenFlags &= ~OF_SHARE_DENY_WRITE;
  1285. fh = OpenFile(pProInfo->lpProFile, &pProInfo->ProBuf, OpenFlags);
  1286. }
  1287. }
  1288. pProInfo->FileHandle = fh;
  1289. /* If we are using a different drive than the last call or this is
  1290. * the first time, clear cluster size so we reread it on next
  1291. * call to WriteString.
  1292. */
  1293. if (byLastDrive != *pProInfo->ProBuf.szPathName)
  1294. pProInfo->wClusterSize = 0;
  1295. if ( fh == -1 )
  1296. goto ReturnNull;
  1297. /* Seek to end of file, allow for CR, LF and NULL */
  1298. llen = _llseek(fh, 0L, 2);
  1299. if (!llen)
  1300. pProInfo->ProFlags |= PRO_CREATED;
  1301. llen += 3;
  1302. if ( llen > MAXBUFLEN )
  1303. llen = MAXBUFLEN; /* Limit to plenty less than 64k */
  1304. /* Now get a buffer */
  1305. hNew = IGlobalReAlloc(pProInfo->hBuffer, llen, GMEM_ZEROINIT);
  1306. if ( !hNew ) {
  1307. ReturnNull:
  1308. return( pProInfo->lpBuffer = (LPSTR)0 );
  1309. }
  1310. /* And now read in the file */
  1311. pProInfo->hBuffer = hNew;
  1312. LockBuffer(pProInfo);
  1313. _llseek(fh, 0L, 0); /* Seek to beginning of file */
  1314. *(int _far *)pProInfo->lpBuffer = 0x2020; /* Bogus spaces */
  1315. len = _lread(fh, pProInfo->lpBuffer, (short)llen-3);
  1316. if ( len == -1 ) {
  1317. UnlockBuffer(pProInfo);
  1318. return( FreeBuffer(pProInfo) );
  1319. }
  1320. if ( len < 2 )
  1321. len = 2; /* Prevent faults in PackBuffer */
  1322. return( PackBuffer(pProInfo, len, OpenFlags & READ_WRITE) );
  1323. }
  1324. /*
  1325. * LockBuffer - Lock the buffer containing the file. Make it
  1326. * moveable and non-discardable.
  1327. * Instead of locking the buffer, we're just going to make it
  1328. * non-discardable and moveable. This is preferable to locking it
  1329. * because all we really care about is that it doesn't get discarded.
  1330. *
  1331. * Parameter:
  1332. * pProInfo Pointer to info describing INI file
  1333. *
  1334. * Returns:
  1335. * LPSTR Pointer to buffer containing file
  1336. */
  1337. LPSTR _fastcall
  1338. LockBuffer(pProInfo)
  1339. PROINFO *pProInfo;
  1340. {
  1341. /* We only have to lock the block if it's marked dirty. Otherwise
  1342. * it's already unlocked.
  1343. */
  1344. if (!(pProInfo->ProFlags & PROUNCLEAN))
  1345. {
  1346. /* Make the block non-discardable */
  1347. IGlobalReAlloc(pProInfo->hBuffer, 0L,
  1348. GMEM_MODIFY + GMEM_MOVEABLE);
  1349. /* All we need here is to dereference the handle. Since
  1350. * this block is now non-discardable, this is all that
  1351. * IGlobalLock() really does.
  1352. */
  1353. pProInfo->lpBuffer = IGlobalLock(pProInfo->hBuffer);
  1354. IGlobalUnlock(pProInfo->hBuffer);
  1355. }
  1356. return pProInfo->lpBuffer;
  1357. }
  1358. /*
  1359. * UnlockBuffer - unlock the buffer, make it discardable and close the file.
  1360. * We don't really have to unlock the buffer (we weren't before anyway
  1361. * even though the comment says so)
  1362. *
  1363. * Parameter:
  1364. * pProInfo Pointer to info describing INI file
  1365. *
  1366. * Returns:
  1367. * nothing
  1368. */
  1369. void _fastcall
  1370. UnlockBuffer(pProInfo)
  1371. PROINFO *pProInfo;
  1372. {
  1373. int fh;
  1374. if (!(pProInfo->ProFlags & PROUNCLEAN))
  1375. IGlobalReAlloc(pProInfo->hBuffer, 0L, GMEM_DISCARDABLE+GMEM_MODIFY);
  1376. fh = pProInfo->FileHandle;
  1377. pProInfo->FileHandle = -1;
  1378. if (fh != -1)
  1379. _lclose(fh);
  1380. }
  1381. /*
  1382. * FreeBuffer - discards the CONTENTS of a buffer containing an INI file
  1383. *
  1384. * Parameter:
  1385. * pProInfo Pointer to info describing INI file
  1386. *
  1387. * Returns:
  1388. * (LPSTR)0
  1389. */
  1390. LPSTR _fastcall
  1391. FreeBuffer(pProInfo)
  1392. PROINFO *pProInfo;
  1393. {
  1394. if ( pProInfo->ProFlags & PROUNCLEAN )
  1395. WriteOutProfiles();
  1396. /* Make the buffer discardable */
  1397. IGlobalReAlloc(pProInfo->hBuffer, 0L, GMEM_DISCARDABLE+GMEM_MODIFY);
  1398. /* Make it zero length, shared, moveable and below the line */
  1399. IGlobalReAlloc(pProInfo->hBuffer, 0L, GMEM_MOVEABLE);
  1400. pProInfo->ProFlags = 0;
  1401. return( pProInfo->lpBuffer = (LPSTR)0 );
  1402. }
  1403. /*
  1404. * PackBuffer - strip blanks comments and ^Zs from an INI file
  1405. *
  1406. * Parameters:
  1407. * pProInfo Pointer to info describing INI file
  1408. * Count Number of characters in the buffer
  1409. * writing Flag indicating we are writing to the file
  1410. *
  1411. * Returns:
  1412. * LPSTR Pointer to the packed buffer
  1413. *
  1414. * NOTE: The use of Count here is DUMB. We should stick a NULL
  1415. * at the end, check for it and toss all the checks on Count.
  1416. */
  1417. LPSTR _fastcall
  1418. PackBuffer(pProInfo, Count, fKeepComments)
  1419. PROINFO *pProInfo;
  1420. int Count;
  1421. int fKeepComments;
  1422. {
  1423. LPSTR Buffer;
  1424. char BASED_ON_LP(Buffer) *psrc;
  1425. char BASED_ON_LP(Buffer) *pdst;
  1426. char BASED_ON_LP(Buffer) *LastValid;
  1427. char nextc;
  1428. Buffer = pProInfo->lpBuffer;
  1429. psrc = pdst = (char BASED_ON_LP(Buffer)*)(WORD)(DWORD)Buffer;
  1430. if ( WinFlags & WF_PMODE )
  1431. fKeepComments = 1;
  1432. if ( fKeepComments )
  1433. pProInfo->ProFlags |= PROCOMMENTS;
  1434. while ( Count ) {
  1435. /* Strip leading spaces and tabs */
  1436. nextc = *psrc;
  1437. if ( nextc == SPACE || nextc == TAB ) {
  1438. /* TAB or SPACE never in lead byte of DBCS, so loop is safe */
  1439. Count--;
  1440. psrc++;
  1441. continue;
  1442. }
  1443. /* Process non-blanks */
  1444. LastValid = pdst;
  1445. do {
  1446. nextc = *psrc++;
  1447. Count--;
  1448. /* Strip comments if real mode and not writing */
  1449. if ( nextc == ';' && !fKeepComments ) {
  1450. while ( Count && nextc != LINEFEED ) {
  1451. /* LINEFEED never in lead byte of DBCS, so loop is safe */
  1452. nextc = *psrc++;
  1453. Count--;
  1454. }
  1455. break;
  1456. }
  1457. /* Copy this character */
  1458. *pdst++ = nextc;
  1459. #ifdef FE_SB
  1460. if ( Count && CIsDBCSLeadByte(nextc) ) {
  1461. *pdst++ = *psrc++;
  1462. Count--;
  1463. }
  1464. #endif
  1465. if ( nextc == '=' ) {
  1466. /* Skip preceeding spaces and tabs */
  1467. pdst = LastValid;
  1468. /* New home for the '=' */
  1469. *pdst++ = nextc;
  1470. /* Skip spaces and tabs again */
  1471. while ( Count ) {
  1472. nextc = *psrc;
  1473. if ( nextc != SPACE && nextc != TAB )
  1474. break;
  1475. Count--;
  1476. psrc++;
  1477. }
  1478. /* Copy remainder of line */
  1479. while ( Count ) {
  1480. Count--;
  1481. /* LINEFEED never in lead byte of DBCS, so loop is safe */
  1482. if ( (*pdst++ = *psrc++) == LINEFEED )
  1483. break;
  1484. }
  1485. break;
  1486. }
  1487. /* End of file or line? */
  1488. if ( Count == 0 || nextc == LINEFEED )
  1489. break;
  1490. /* Strip trailing spaces */
  1491. if ( nextc == SPACE || nextc == TAB )
  1492. continue;
  1493. LastValid = pdst;
  1494. } while ( Count );
  1495. /* Here if end of line or file */
  1496. }
  1497. /* Here if end of file; skip trailing ^Zs */
  1498. for ( ; ; ) {
  1499. if ( pdst == Buffer )
  1500. break;
  1501. if ( *--pdst != CTRLZ ) {
  1502. pdst++;
  1503. break;
  1504. }
  1505. }
  1506. *pdst++ = CR;
  1507. *pdst++ = LINEFEED;
  1508. *pdst++ = 0;
  1509. IGlobalUnlock(pProInfo->hBuffer);
  1510. IGlobalReAlloc(pProInfo->hBuffer, (long)((LPSTR)pdst - Buffer), 0);
  1511. Buffer = LockBuffer(pProInfo);
  1512. pProInfo->BufferLen = (unsigned)pdst;
  1513. return(Buffer);
  1514. }
  1515. #ifdef FE_SB
  1516. /*
  1517. * C interface to FarMyIsDBCSLeadByte
  1518. *
  1519. * Parameter:
  1520. * c character to be tested
  1521. *
  1522. * Returns:
  1523. * 1 It is a lead byte
  1524. * 0 It isn't a lead byte
  1525. */
  1526. CIsDBCSLeadByte(c)
  1527. char c;
  1528. {
  1529. _asm {
  1530. mov al, c
  1531. call FarMyIsDBCSLeadByte
  1532. cmc ; Set carry if lead byte
  1533. mov ax, 0 ; Set return value to 0, preserve flags
  1534. adc al, 0 ; Set to one if carry set
  1535. }
  1536. }
  1537. #endif
  1538. /*
  1539. * WriteString
  1540. *
  1541. * Adds/deletes sections/lines in an INI file
  1542. *
  1543. * Parameters:
  1544. * pProInfo pointer to info on the file
  1545. * lpSection pointer to the section name we want
  1546. * lpKeyName key name to change or add
  1547. * NULL means delete section
  1548. * lpString string to add to file
  1549. * NULL means delete line
  1550. *
  1551. * Returns:
  1552. * bResult Success/Fail
  1553. */
  1554. WriteString(pProInfo, lpSection, lpKeyName, lpString)
  1555. PROINFO *pProInfo;
  1556. LPSTR lpSection;
  1557. LPSTR lpKeyName;
  1558. LPSTR lpString;
  1559. {
  1560. LPSTR ptrTmp;
  1561. short WhatIsMissing;
  1562. short nchars;
  1563. short fh;
  1564. long fp;
  1565. short SectLen = 0;
  1566. short KeyLen = 0;
  1567. short ResultLen = 0;
  1568. SEGMENT BufferSeg;
  1569. register char BASED_ON_SEG(BufferSeg) *bp;
  1570. /* Debugging noise */
  1571. /* Assert that we have something to do! */
  1572. if ( (SEGMENT)lpSection == NULL && (SEGMENT)lpKeyName == NULL
  1573. && (SEGMENT)lpString == NULL ) {
  1574. FreeBuffer(pProInfo); /* FEATURE! */
  1575. return(0);
  1576. }
  1577. /* If buffer does not already contain comments, free it */
  1578. if ( !(pProInfo->ProFlags & PROCOMMENTS) )
  1579. FreeBuffer(pProInfo);
  1580. /* Read the file into a buffer, preserving comments */
  1581. ptrTmp = BufferInit(pProInfo, READ_WRITE);
  1582. if ( !ptrTmp )
  1583. return(0);
  1584. /* Abort now if read only file */
  1585. if ( pProInfo->ProFlags & PROREADONLY )
  1586. goto GrodyError;
  1587. /* Set bp to point in buffer where we will add stuff */
  1588. BufferSeg = (SEGMENT)ptrTmp;
  1589. bp = pProInfo->BufferLen + (char BASED_ON_SEG(BufferSeg)*)
  1590. (WORD)(DWORD)ptrTmp - 1;
  1591. /*
  1592. * Now see what we have to do to the file by
  1593. * searching for section and keyname.
  1594. */
  1595. nchars = 0;
  1596. /* See if section exists */
  1597. if ( !(ptrTmp = FindSection(ptrTmp, lpSection)) ) {
  1598. /* No Section. If deleting anything, stop now */
  1599. if ( !lpKeyName || !lpString )
  1600. goto NothingToDo;
  1601. /* Need to add section and keyname */
  1602. WhatIsMissing = NOSECTION;
  1603. } else {
  1604. /* Found the section, save pointer to it */
  1605. bp = (char BASED_ON_SEG(BufferSeg)*)(WORD)(DWORD)ptrTmp;
  1606. /* If lpKeyName NULL, delete the section */
  1607. if ( !lpKeyName ) {
  1608. WhatIsMissing = REMOVESECTION;
  1609. } else {
  1610. /* Look for the keyname in the section */
  1611. if ( !(ptrTmp = FindKey(bp, lpKeyName)) ) {
  1612. /* No KeyName, stop if deleting it */
  1613. if ( !lpString )
  1614. goto NothingToDo;
  1615. WhatIsMissing = NOKEY;
  1616. /* Insert new keyname
  1617. at the end of the section */
  1618. while ( *bp && (*bp != SECT_LEFT || *(bp-1) != LINEFEED) )
  1619. bp++;
  1620. } else {
  1621. /* Found the keyname, save pointer */
  1622. bp = (char BASED_ON_SEG(BufferSeg)*)
  1623. (WORD)(DWORD)ptrTmp;
  1624. /* NULL lpString means delete it */
  1625. if ( !lpString )
  1626. WhatIsMissing = REMOVEKEY;
  1627. else {
  1628. /*
  1629. * Compare the existing string with the
  1630. * string we are supposed to replace it
  1631. * with. If they are the same, there
  1632. * is no need to rewrite the file, so
  1633. * we abort now.
  1634. */
  1635. if ( !IsItTheSame((LPSTR)bp, lpString) )
  1636. goto NothingToDo;
  1637. /*
  1638. * Count characters in old result.
  1639. * The file will be shrinking by
  1640. * this many characters.
  1641. */
  1642. while ( *bp++ != CR )
  1643. nchars--;
  1644. bp = (char BASED_ON_SEG(BufferSeg)*)
  1645. (WORD)(DWORD)ptrTmp;
  1646. WhatIsMissing = NEWRESULT;
  1647. }
  1648. }
  1649. }
  1650. }
  1651. /*
  1652. * If we will be adding to the file, grow the buffer
  1653. * to the size we will need, then make an appropriate
  1654. * sized hole in the buffer.
  1655. */
  1656. switch ( WhatIsMissing ) {
  1657. case NOSECTION:
  1658. /* Need to add section */
  1659. SectLen = Cstrlen(lpSection);
  1660. nchars = SectLen + 4; /* for []<CR><LF> */
  1661. /* Fall through for KeyName and result */
  1662. case NOKEY:
  1663. /* Need to add key name */
  1664. KeyLen = Cstrlen(lpKeyName);
  1665. nchars += KeyLen + 3; /* for =<CR><LF> */
  1666. /* For new key or section, skip back to previous line */
  1667. while ( bp > pProInfo->lpBuffer ) {
  1668. bp--;
  1669. if ( *bp != CR && *bp != LINEFEED )
  1670. break;
  1671. }
  1672. if ( bp != pProInfo->lpBuffer )
  1673. bp += 3;
  1674. /* Fall through for result */
  1675. /* If not at start of buffer, add room for extra CR/LF */
  1676. if ((WORD)bp && WhatIsMissing == NOSECTION)
  1677. nchars += 2;
  1678. case NEWRESULT:
  1679. /* Need to change/add result */
  1680. /* nchars may be -<current length of result> */
  1681. ResultLen = Cstrlen(lpString);
  1682. nchars += ResultLen;
  1683. /* Grow the buffer if necessary */
  1684. if ( nchars > 0 ) {
  1685. IGlobalUnlock(pProInfo->hBuffer);
  1686. fp = nchars + (long)pProInfo->BufferLen;
  1687. /* Ensure buffer will be plenty less than 64k */
  1688. /* and grow to new size */
  1689. if ( fp > MAXBUFLEN || !IGlobalReAlloc(pProInfo->hBuffer, fp, 0) ) {
  1690. /* Undo above Unlock */
  1691. IGlobalLock(pProInfo->hBuffer);
  1692. goto GrodyError;
  1693. }
  1694. pProInfo->lpBuffer = IGlobalLock(pProInfo->hBuffer);
  1695. BufferSeg = (SEGMENT)pProInfo->lpBuffer;
  1696. }
  1697. /* In order to fix bug #4672 and other ugly things
  1698. * that happen when we run out of disk space,
  1699. * we want to see if there is room to write the
  1700. * buffer. We know that the file can actually only
  1701. * grow on cluster boundaries, but rather than get
  1702. * the cluster size. If we don't have the cluster
  1703. * size yet, we have to get it from DOS.
  1704. */
  1705. if (!pProInfo->wClusterSize)
  1706. {
  1707. WORD wTemp;
  1708. /* Get drive letter */
  1709. wTemp = *pProInfo->ProBuf.szPathName - 'A' + 1;
  1710. _asm
  1711. {
  1712. mov ah,1ch ;Drive parameters
  1713. mov dl,BYTE PTR wTemp
  1714. push ds
  1715. int 21h
  1716. pop ds
  1717. cmp al,0ffh ;Error?
  1718. jnz DPOk ;No
  1719. mov al,1
  1720. mov cx,512 ;Default
  1721. DPOk: cbw ;Secs per cluster WORD
  1722. mul cx ;AX = bytes/cluster
  1723. mov wTemp,ax
  1724. }
  1725. if (!wTemp)
  1726. pProInfo->wClusterSize = 512;
  1727. else
  1728. pProInfo->wClusterSize = wTemp;
  1729. }
  1730. /* Now see if we're going past a cluster length */
  1731. if ((pProInfo->ProFlags & PRO_CREATED) ||
  1732. (((pProInfo->BufferLen + nchars) ^ pProInfo->BufferLen)
  1733. & ~(pProInfo->wClusterSize - 1)))
  1734. {
  1735. int fh;
  1736. /* Make sure that we only do this once for a newly-
  1737. * created file because this will handle the
  1738. * growing to one cluster case.
  1739. */
  1740. pProInfo->ProFlags &= ~PRO_CREATED;
  1741. fh = pProInfo->FileHandle;
  1742. /* Make sure the file is open and exists. If not,
  1743. * we have to open the file. We are guaranteed
  1744. * at least that the file exists in this case.
  1745. * Note that UnlockBuffer closes the file
  1746. * that we open here.
  1747. */
  1748. if (fh == -1)
  1749. {
  1750. fh = OpenFile(pProInfo->lpProFile,&pProInfo->ProBuf,OF_REOPEN+READ_WRITE+OF_SHARE_DENY_WRITE);
  1751. /* Sharing violation. Let's try compabitility mode. */
  1752. if ( (fh == -1) && (pProInfo->ProBuf.nErrCode == SHARINGVIOLATION ) ){
  1753. fh = OpenFile(pProInfo->lpProFile,&pProInfo->ProBuf,OF_REOPEN+READ_WRITE);
  1754. }
  1755. pProInfo->FileHandle = fh;
  1756. }
  1757. /* Try to grow the file to the right length */
  1758. if(_llseek(fh, pProInfo->BufferLen + nchars, 0) !=
  1759. pProInfo->BufferLen + nchars ||
  1760. _lwrite(fh, " ", 1) != 1)
  1761. goto GrodyError;
  1762. }
  1763. /* Now, make room in the buffer for this new stuff */
  1764. if ( nchars )
  1765. MakeRoom((LPSTR)bp, nchars, &pProInfo->BufferLen);
  1766. /* Now copy in the new info */
  1767. switch ( WhatIsMissing ) {
  1768. case NOSECTION:
  1769. /* Create the new section */
  1770. (int)bp = InsertSection((LPSTR)bp, lpSection, SectLen);
  1771. /* FALL THROUGH */
  1772. case NOKEY:
  1773. (int)bp = InsertKey((LPSTR)bp, lpKeyName, KeyLen);
  1774. /* FALL THROUGH */
  1775. case NEWRESULT:
  1776. (int) bp = InsertResult((LPSTR)bp, lpString, ResultLen);
  1777. }
  1778. break;
  1779. /* Handle deleting sections or KeyNames */
  1780. case REMOVESECTION:
  1781. DeleteSection((LPSTR)bp, pProInfo);
  1782. break;
  1783. case REMOVEKEY:
  1784. DeleteKey((LPSTR)bp, pProInfo);
  1785. break;
  1786. }
  1787. pProInfo->ProFlags |= PROUNCLEAN;
  1788. fProfileDirty = 1;
  1789. NothingToDo:
  1790. UnlockBuffer(pProInfo);
  1791. return(1);
  1792. /* I really hate the GOTO, but in order to clean up, this is much
  1793. * more efficient...
  1794. */
  1795. GrodyError:
  1796. UnlockBuffer(pProInfo);
  1797. return 0;
  1798. }
  1799. /*
  1800. * WriteOutProfiles
  1801. *
  1802. * Called on a task switch or at exit time
  1803. *
  1804. * If we have a dirty profile buffer, write it.
  1805. */
  1806. void API
  1807. WriteOutProfiles(void)
  1808. {
  1809. LPSTR ptrTmp;
  1810. int fh;
  1811. PROINFO *pProInfo;
  1812. int nwritten;
  1813. /* Make sure that we don't get called through a DOS call. This
  1814. * flag is tested in I21ENTRY.ASM in the Int 21h hook to see
  1815. * if the profiles should be flushed.
  1816. */
  1817. ++fWriteOutProfilesReenter;
  1818. for ( pProInfo = &WinIniInfo; ; pProInfo = &PrivateProInfo ) {
  1819. if ( !(pProInfo->ProFlags & PROUNCLEAN) )
  1820. goto NoWrite;
  1821. if (
  1822. /* Try read/write with sharing flags, then try compabitility mode, then try to create it. */
  1823. ( (fh = OpenFile(NULL, &pProInfo->ProBuf, OF_REOPEN | READ_WRITE | OF_SHARE_DENY_WRITE)) == -1)
  1824. && ( (fh = OpenFile(NULL, &pProInfo->ProBuf, OF_REOPEN | READ_WRITE)) == -1)
  1825. && ( (fh = OpenFile(NULL, &pProInfo->ProBuf, OF_REOPEN | OF_CREATE)) == -1) ){
  1826. goto NoWrite;
  1827. }
  1828. pProInfo->FileHandle = fh;
  1829. /* Finally write the file */
  1830. ptrTmp = pProInfo->lpBuffer;
  1831. nwritten = _lwrite(fh, ptrTmp, pProInfo->BufferLen-3);
  1832. if ( nwritten == pProInfo->BufferLen-3 ) {
  1833. _lwrite(fh, ptrTmp, 0); /* Mark end of file */
  1834. pProInfo->ProFlags &= ~(PROUNCLEAN | PRO_CREATED);
  1835. UnlockBuffer(pProInfo);
  1836. } else {
  1837. _lclose(fh);
  1838. }
  1839. NoWrite:
  1840. if ( pProInfo == &PrivateProInfo )
  1841. break;
  1842. }
  1843. fProfileDirty = 0;
  1844. --fWriteOutProfilesReenter;
  1845. }
  1846. /*
  1847. * See if two character strings are the same.
  1848. * Special routine since one is terminated with <CR>.
  1849. * Returns zero if the strings match.
  1850. */
  1851. IsItTheSame(CRstring, NullString)
  1852. LPSTR CRstring;
  1853. LPSTR NullString;
  1854. {
  1855. _asm {
  1856. push ds
  1857. les di, CRstring ; CR terminated string
  1858. lds si, NullString ; Null terminated string
  1859. xor ah, ah ; High byte of return value
  1860. stci10:
  1861. mov al,es:[di] ; Get next character
  1862. cmp al,0Dh ; CR?
  1863. jnz stci15 ; no, compare it
  1864. mov al,[si] ; yes, strings equal if at end
  1865. jmp stciex
  1866. stci15:
  1867. mov cl,[si]
  1868. inc si
  1869. inc di
  1870. cmp al,cl ; Still matching chars?
  1871. jz stci10 ; Yes, go try the next char.
  1872. mov al, 1 ; Didn't match
  1873. stciex:
  1874. pop ds
  1875. }
  1876. }
  1877. /*
  1878. * Create or close a hole in the buffer.
  1879. * Used to create room for a new section,
  1880. * keyname or result and to remove unwanted
  1881. * sections, keynames or results.
  1882. *
  1883. * Parameters:
  1884. * lp position in buffer to add/remove characters
  1885. * nchars number of characters to add/remove
  1886. * pAdjust pointer to variable containing current
  1887. * size of the buffer
  1888. *
  1889. * Side effects:
  1890. * *pAdjust is changed by nchars
  1891. *
  1892. * Returns:
  1893. * nothing
  1894. */
  1895. MakeRoom(lp, nChars, pAdjust)
  1896. LPSTR lp;
  1897. short nChars;
  1898. int *pAdjust;
  1899. {
  1900. short BufLen = *pAdjust;
  1901. if ( nChars < 0 )
  1902. _asm {
  1903. push ds
  1904. les di, lp ; Where characters will be taken
  1905. push es
  1906. pop ds
  1907. mov si, di ; End of area
  1908. sub si, nChars ; Remember nChars is negative
  1909. mov cx, BufLen
  1910. sub cx, si ; Calculate # characters to move
  1911. cld
  1912. rep movsb ; Copy characters down
  1913. pop ds
  1914. } else _asm {
  1915. push ds
  1916. mov es, word ptr lp[2] ; Get segment to copy in
  1917. mov ds, word ptr lp[2]
  1918. mov si, BufLen ; We will be moving backwards
  1919. mov cx, si
  1920. dec si ; Adjust pointer for move
  1921. mov di, si ; so start at end of the buffer
  1922. sub cx, word ptr lp ; Number of characters to move
  1923. add di, nChars
  1924. std ; Backwards move
  1925. rep movsb ; Copy characters up
  1926. cld
  1927. pop ds
  1928. }
  1929. *pAdjust += nChars;
  1930. }
  1931. /*
  1932. * Delete a section from the buffer,
  1933. * preserving comments since they may
  1934. * relate to the next section
  1935. *
  1936. * Parameters:
  1937. * lp pointer to section returned by FindSection
  1938. * pProInfo pointer to INI file info
  1939. *
  1940. * Returns:
  1941. * nothing
  1942. */
  1943. DeleteSection(lp, pProInfo)
  1944. LPSTR lp;
  1945. PROINFO *pProInfo;
  1946. {
  1947. int nRemoved;
  1948. char BASED_ON_LP(lp) *SectEnd;
  1949. _asm {
  1950. cld
  1951. push ds
  1952. lds si, lp
  1953. BackToStart:
  1954. dec si ; Skip backwards to start of the section
  1955. cmp ds:[si], SECT_LEFT
  1956. jne BackToStart
  1957. mov di, si
  1958. push ds
  1959. pop es ; ES:DI points to start of section
  1960. inc si ; DS:SI points to the '[', skip it
  1961. RemoveLoop:
  1962. lodsb ; Get next character in section
  1963. cmp al, ';' ; Is it a comment
  1964. jne NotComment
  1965. CopyComment:
  1966. stosb ; Save this character
  1967. cmp al, LINEFEED ; Copy to end of the line
  1968. je RemoveLoop
  1969. lodsb ; And get the next one
  1970. jmp CopyComment
  1971. NotComment:
  1972. cmp al, SECT_LEFT ; So is it the next section?
  1973. je EndSection
  1974. or al, al ; or the end of the buffer?
  1975. jne SkipLine
  1976. sub si, 2 ; Extra CR & LF at end of buffer
  1977. jmp short EndSection
  1978. SkipLine:
  1979. cmp al, LINEFEED ; Nothing interesting, so skip line
  1980. je RemoveLoop
  1981. lodsb
  1982. jmp SkipLine
  1983. EndSection:
  1984. dec si ; Back to the character
  1985. mov SectEnd, si ; where the search stopped
  1986. mov word ptr lp, di ; End of copied comments (if any)
  1987. sub si, di
  1988. mov nRemoved, si ; Number of characters removed
  1989. pop ds
  1990. }
  1991. MakeRoom(lp, -nRemoved, &pProInfo->BufferLen);
  1992. }
  1993. /*
  1994. * Delete a keyname from the buffer
  1995. *
  1996. * Parameters:
  1997. * lp pointer to keyname returned by FindKey
  1998. * pProInfo pointer to INI file info
  1999. *
  2000. * Returns:
  2001. * nothing
  2002. */
  2003. DeleteKey(lp, pProInfo)
  2004. LPSTR lp;
  2005. PROINFO *pProInfo;
  2006. {
  2007. int nRemoved;
  2008. char BASED_ON_LP(lp) *KeyEnd;
  2009. _asm {
  2010. cld
  2011. les di, lp
  2012. BackToStart:
  2013. dec di ; Skip backwards to start of the line
  2014. cmp es:[di], LINEFEED
  2015. jne BackToStart
  2016. inc di
  2017. mov word ptr lp, di ; Save start of the line
  2018. mov cx, -1
  2019. mov al, LINEFEED
  2020. repne scasb ; Scan to end of the line
  2021. sub di, word ptr lp
  2022. mov nRemoved, di ; Length of line
  2023. }
  2024. MakeRoom(lp, -nRemoved, &pProInfo->BufferLen);
  2025. }
  2026. /*
  2027. * Insert a new section in the buffer.
  2028. * A hole has already been created for it.
  2029. * This merely copies the string, places
  2030. * '[]'s around it and a CR, LF after it.
  2031. * Returns a pointer to immediately
  2032. * after the section header in the buffer.
  2033. *
  2034. * Parameters:
  2035. * lpDest pointer to where to add the section
  2036. * lpSrc pointer to the section name
  2037. * count length of lpSrc
  2038. */
  2039. InsertSection(lpDest, lpSrc, count)
  2040. LPSTR lpDest;
  2041. LPSTR lpSrc;
  2042. short count;
  2043. {
  2044. _asm {
  2045. cld
  2046. push ds
  2047. les di, lpDest
  2048. lds si, lpSrc
  2049. or di,di ; If at start of buffer, no prefix
  2050. jz IS_SkipPrefix
  2051. mov ax, LINEFEED SHL 8 + CR ; Prefix with CR/LF
  2052. stosw
  2053. IS_SkipPrefix:
  2054. mov al, SECT_LEFT ; '[' first
  2055. stosb
  2056. mov cx, count ; Now the section name
  2057. rep movsb
  2058. mov al, SECT_RIGHT ; and the ']'
  2059. stosb
  2060. mov ax, LINEFEED SHL 8 + CR ; finally, CR, LF
  2061. stosw
  2062. pop ds
  2063. mov ax, di ; Return pointer to char after header
  2064. }
  2065. }
  2066. /*
  2067. * Insert a new keyname in the buffer.
  2068. * This copies the keyname and adds
  2069. * an '='. It is assumed that InsertResult()
  2070. * will terminate the line.
  2071. * A pointer to the buffer immediately after
  2072. * the '=' is returned.
  2073. *
  2074. * Parameters:
  2075. * lpDest pointer to where to add the keyname
  2076. * lpSrc pointer to the keyname
  2077. * count length of lpSrc
  2078. */
  2079. InsertKey(lpDest, lpSrc, count)
  2080. LPSTR lpDest;
  2081. LPSTR lpSrc;
  2082. short count;
  2083. {
  2084. _asm {
  2085. cld
  2086. push ds
  2087. les di, lpDest
  2088. lds si, lpSrc
  2089. mov cx, count ; Copy the KeyName
  2090. rep movsb
  2091. mov al, '=' ; add the '='
  2092. stosb
  2093. mov ax, di ; Pointer to char after the '='
  2094. pop ds
  2095. }
  2096. }
  2097. /*
  2098. * Add a new result string to the buffer.
  2099. * It assumes that the keyname and '=' are
  2100. * already there. This routine may be
  2101. * overwriting an existing result. The result
  2102. * is terminated with a CR, LR.
  2103. *
  2104. * Parameters:
  2105. * lpDest pointer to where to add the result
  2106. * lpSrc pointer to the result
  2107. * count length of lpSrc
  2108. */
  2109. InsertResult(lpDest, lpSrc, count)
  2110. LPSTR lpDest;
  2111. LPSTR lpSrc;
  2112. short count;
  2113. {
  2114. _asm {
  2115. cld
  2116. push ds
  2117. les di, lpDest
  2118. lds si, lpSrc
  2119. mov cx, count ; Copy the result
  2120. rep movsb
  2121. mov ax, LINEFEED SHL 8 + CR ; finally, CR, LF
  2122. stosw ; This may overwrite existing CR, LF
  2123. mov ax, di
  2124. pop ds
  2125. }
  2126. }
  2127. /*
  2128. * GetFileAttr
  2129. *
  2130. * DOS call to Get file attributes
  2131. GetFileAttr(szFile)
  2132. LPSTR szFile;
  2133. {
  2134. _asm {
  2135. int 3
  2136. xor cx, cx ; In case of failure
  2137. lds dx, szFile
  2138. mov ax, 4300h
  2139. int 21h
  2140. mov ax, cx
  2141. }
  2142. }
  2143. */