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.

802 lines
16 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1990 - 1999
  6. //
  7. // File: util.hxx
  8. //
  9. //--------------------------------------------------------------------------
  10. /* --------------------------------------------------------------------
  11. Internal Header File for RPC Runtime Library
  12. -------------------------------------------------------------------- */
  13. #ifndef __UTIL_HXX__
  14. #define __UTIL_HXX__
  15. #ifndef __SYSINC_H__
  16. #error Needs sysinc.h
  17. #endif
  18. START_C_EXTERN
  19. #ifndef ARGUMENT_PRESENT
  20. #define ARGUMENT_PRESENT(Argument) (Argument != 0)
  21. #endif // ARGUMENT_PRESENT
  22. #ifdef NULL
  23. #undef NULL
  24. #endif
  25. #define NULL (0)
  26. #define Nil 0
  27. #ifdef TRUE
  28. #undef TRUE
  29. #endif
  30. #ifdef FALSE
  31. #undef FALSE
  32. #endif
  33. #define _NOT_COVERED_ (0)
  34. #define FALSE (0)
  35. #define TRUE (1)
  36. //
  37. // Expose the external logging hook on all builds.
  38. //
  39. #define RPC_ENABLE_WMI_TRACE
  40. #define RPC_ERROR_LOGGING
  41. #ifdef DBG
  42. //#define RPC_ENABLE_TEST_HOOKS
  43. #ifndef RPC_LOGGING
  44. #define RPC_LOGGING
  45. #endif
  46. #endif
  47. unsigned long
  48. SomeLongValue (
  49. );
  50. unsigned short
  51. SomeShortValue (
  52. );
  53. unsigned short
  54. AnotherShortValue (
  55. );
  56. unsigned char
  57. SomeCharacterValue (
  58. );
  59. extern int
  60. RpcpCheckHeap (
  61. void
  62. );
  63. int
  64. IsMgmtIfUuid(
  65. UUID PAPI * Uuid
  66. );
  67. END_C_EXTERN
  68. void
  69. PerformGarbageCollection (
  70. void
  71. );
  72. BOOL
  73. GarbageCollectionNeeded (
  74. IN BOOL fOneTimeCleanup,
  75. IN unsigned long GarbageCollectInterval
  76. );
  77. RPC_STATUS CreateGarbageCollectionThread (
  78. void
  79. );
  80. RPC_STATUS
  81. EnableIdleConnectionCleanup (
  82. void
  83. );
  84. RPC_STATUS
  85. EnableIdleLrpcSContextsCleanup (
  86. void
  87. );
  88. void
  89. GetMaxRpcSizeAndThreadPoolParameters (
  90. void
  91. );
  92. #ifdef RPC_DELAYED_INITIALIZATION
  93. extern int RpcHasBeenInitialized;
  94. extern RPC_STATUS
  95. PerformRpcInitialization (
  96. void
  97. );
  98. #define InitializeIfNecessary() \
  99. if ( RpcHasBeenInitialized == 0 ) \
  100. { \
  101. RPC_STATUS RpcStatus; \
  102. \
  103. RpcStatus = PerformRpcInitialization(); \
  104. if ( RpcStatus != RPC_S_OK ) \
  105. return(RpcStatus); \
  106. }
  107. #define AssertRpcInitialized() ASSERT( RpcHasBeenInitialized != 0 )
  108. #else /* RPC_DELAYED_INITIALIZATION */
  109. #define InitializeIfNecessary()
  110. #define AssertRpcInitialized()
  111. #define PerformRpcInitialization()
  112. #endif /* RPC_DELAYED_INITIALIZATION */
  113. RPC_CHAR *
  114. DuplicateString (
  115. IN RPC_CHAR PAPI * String
  116. );
  117. #ifdef UNICODE
  118. extern RPC_STATUS
  119. AnsiToUnicodeString (
  120. IN unsigned char * String,
  121. OUT UNICODE_STRING * UnicodeString
  122. );
  123. extern unsigned char *
  124. UnicodeToAnsiString (
  125. IN RPC_CHAR * WideCharString,
  126. OUT RPC_STATUS * RpcStatus
  127. );
  128. #endif // UNICODE
  129. void
  130. DestroyContextHandlesForGuard (
  131. IN PVOID Context,
  132. IN BOOL RundownContextHandle,
  133. IN void *CtxGuard
  134. );
  135. // forward definition
  136. class ContextCollection;
  137. RPC_STATUS
  138. NDRSContextInitializeCollection (
  139. IN ContextCollection **ContextCollectionPlaceholder
  140. );
  141. #if DBG
  142. void
  143. RpcpInterfaceForCallDoesNotUseStrict (
  144. IN RPC_BINDING_HANDLE BindingHandle
  145. );
  146. #endif
  147. inline unsigned short
  148. RpcpByteSwapShort (unsigned short Value)
  149. {
  150. return (RtlUshortByteSwap(Value));
  151. }
  152. inline unsigned long
  153. RpcpByteSwapLong (unsigned long Value)
  154. {
  155. return (RtlUlongByteSwap(Value));
  156. }
  157. typedef union tagFastCopyLUIDAccess
  158. {
  159. LUID Luid;
  160. __int64 FastAccess;
  161. } FastCopyLUIDAccess;
  162. inline void FastCopyLUIDAligned (LUID *TargetLUID, const LUID *SourceLUID)
  163. {
  164. FastCopyLUIDAccess *EffectiveSourceLUID = (FastCopyLUIDAccess *)SourceLUID;
  165. FastCopyLUIDAccess *EffectiveTargetLUID = (FastCopyLUIDAccess *)TargetLUID;
  166. #if defined(_WIN64)
  167. ASSERT((((ULONG_PTR)EffectiveSourceLUID) % 8) == 0);
  168. ASSERT((((ULONG_PTR)EffectiveTargetLUID) % 8) == 0);
  169. #endif
  170. EffectiveTargetLUID->FastAccess = EffectiveSourceLUID->FastAccess;
  171. }
  172. inline void FastCopyLUID (LUID *TargetLUID, LUID *SourceLUID)
  173. {
  174. FastCopyLUIDAccess *EffectiveSourceLUID = (FastCopyLUIDAccess *)SourceLUID;
  175. FastCopyLUIDAccess *EffectiveTargetLUID = (FastCopyLUIDAccess *)TargetLUID;
  176. #if !defined(_WIN64)
  177. FastCopyLUIDAligned(TargetLUID, SourceLUID);
  178. #else
  179. TargetLUID->HighPart = SourceLUID->HighPart;
  180. TargetLUID->LowPart = SourceLUID->LowPart;
  181. #endif
  182. }
  183. // returns non-zero if equal
  184. inline BOOL FastCompareLUIDAligned (const LUID *TargetLUID, const LUID *SourceLUID)
  185. {
  186. FastCopyLUIDAccess *EffectiveSourceLUID = (FastCopyLUIDAccess *)SourceLUID;
  187. FastCopyLUIDAccess *EffectiveTargetLUID = (FastCopyLUIDAccess *)TargetLUID;
  188. #if defined(_WIN64)
  189. ASSERT((((ULONG_PTR)EffectiveSourceLUID) % 8) == 0);
  190. ASSERT((((ULONG_PTR)EffectiveTargetLUID) % 8) == 0);
  191. #endif
  192. return (EffectiveTargetLUID->FastAccess == EffectiveSourceLUID->FastAccess);
  193. }
  194. inline BOOL FastCompareLUID (LUID *TargetLUID, LUID *SourceLUID)
  195. {
  196. FastCopyLUIDAccess *EffectiveSourceLUID = (FastCopyLUIDAccess *)SourceLUID;
  197. FastCopyLUIDAccess *EffectiveTargetLUID = (FastCopyLUIDAccess *)TargetLUID;
  198. #if !defined(_WIN64)
  199. return FastCompareLUIDAligned(TargetLUID, SourceLUID);
  200. #else
  201. return ((TargetLUID->HighPart == SourceLUID->HighPart)
  202. && (TargetLUID->LowPart == SourceLUID->LowPart));
  203. #endif
  204. }
  205. const RPC_CHAR *
  206. FastGetImageBaseName (
  207. void
  208. );
  209. //
  210. // System features - constant after InitializeIfNecessary.
  211. //
  212. // Just contants on non-NT systems
  213. //
  214. extern DWORD gPageSize;
  215. extern DWORD gThreadTimeout;
  216. extern UINT gNumberOfProcessors;
  217. extern DWORD gMaxRpcSize;
  218. extern DWORD gProrateStart;
  219. extern DWORD gProrateMax;
  220. extern DWORD gProrateFactor;
  221. extern BOOL gfServerPlatform;
  222. extern ULONGLONG gPhysicalMemorySize; // in megabytes
  223. // if non-zero, we're in paged bcache (paged buffers mode)
  224. extern BOOL fPagedBCacheMode;
  225. // if non-zero, we may be in lsa. This is maybe, because
  226. // conclusive check is too expensive, and the only
  227. // way we use this flag is to avoid some optimizations
  228. // that can result in deadlock in lsa.
  229. extern BOOL fMaybeLsa;
  230. //
  231. // constants for LogEvent(),
  232. //
  233. #define SU_HANDLE 'h'
  234. #define SU_CCONN 'n'
  235. #define SU_SCONN 'N'
  236. #define SU_CASSOC 'a'
  237. #define SU_SASSOC 'A'
  238. #define SU_CCALL 'c'
  239. #define SU_SCALL 'C'
  240. #define SU_PACKET 'p'
  241. #define SU_CENDPOINT 'e'
  242. #define SU_ENGINE 'E'
  243. #define SU_ASSOC '.'
  244. #define SU_MUTEX 'm'
  245. #define SU_STABLE 'T'
  246. #define SU_ADDRESS 'D'
  247. #define SU_HEAP 'H'
  248. #define SU_BCACHE 'b'
  249. #define SU_REFOBJ 'r'
  250. #define SU_THREAD 't'
  251. #define SU_TRANS_CONN 'o'
  252. #define SU_EVENT 'v'
  253. #define SU_EXCEPT 'x'
  254. #define SU_CTXHANDLE 'l'
  255. #define SU_EEINFO 'I'
  256. #define SU_GC 'G'
  257. #define SU_HTTPv2 '2'
  258. #define EV_CREATE 'C'
  259. #define EV_DELETE 'D'
  260. #define EV_START 'c'
  261. #define EV_STOP 'd'
  262. #define EV_INC '+'
  263. #define EV_DEC '-'
  264. #define EV_PROC 'p'
  265. #define EV_ACK 'a'
  266. #define EV_CALLBACK 'L'
  267. #define EV_NOTIFY 'N'
  268. #define EV_APC 'A'
  269. #define EV_STATUS 'S'
  270. #define EV_DISASSOC 'x'
  271. #define EV_STATE '='
  272. #define EV_POP 'P'
  273. #define EV_PUSH 'Q'
  274. #define EV_PKT_IN 'k'
  275. #define EV_PKT_OUT 'K'
  276. #define EV_BUFFER_IN 'b'
  277. #define EV_BUFFER_OUT 'B'
  278. #define EV_BUFFER_FAIL 'X'
  279. #define EV_ABORT 'R'
  280. #define EV_SET 's'
  281. // for debugging. A packet can be dropped or delayed.
  282. //
  283. #define EV_DROP '*'
  284. #define EV_DELAY '#'
  285. #define EV_PRUNE 'p'
  286. // SU_SCONN: a call is being transferred to another connection during auto-reconnect.
  287. //
  288. #define EV_TRANSFER 'T'
  289. // SU_CASSOC: the dynamic endpoint has been resolved into a real endpoint
  290. //
  291. #define EV_RESOLVED 'r'
  292. // SU_ENGINE: window size and selective-ack bits from a FACK or NOCALL
  293. //
  294. #define EV_WINDOW 'w'
  295. // SU_SCALL: the call was removed from the connection's active list
  296. #define EV_REMOVED 'm'
  297. // SU_SCALL: Cleanup() was called with refcount > 0
  298. #define EV_CLEANUP ','
  299. #define EV_BHCOPY 'O'
  300. #define EV_ALLOCATE 't'
  301. #define EV_OPER 'o'
  302. //
  303. //
  304. #define EV_SEC_INIT1 'i'
  305. #define EV_SEC_INIT3 'I'
  306. #define EV_SEC_ACCEPT1 'j'
  307. #define EV_SEC_ACCEPT3 'J'
  308. #define IN_CHANNEL_STATE (UlongToPtr(0))
  309. #define OUT_CHANNEL_STATE (UlongToPtr(1))
  310. #define MAX_RPC_EVENT 4096
  311. #define STACKTRACE_DEPTH 4
  312. struct RPC_EVENT
  313. {
  314. DWORD Thread;
  315. DWORD Time;
  316. unsigned char Subject;
  317. unsigned char Verb;
  318. void * SubjectPointer;
  319. void * ObjectPointer;
  320. ULONG_PTR Data;
  321. void * EventStackTrace[STACKTRACE_DEPTH];
  322. };
  323. extern void
  324. TrulyLogEvent(
  325. IN unsigned char Subject,
  326. IN unsigned char Verb,
  327. IN void * SubjectPointer,
  328. IN void * ObjectPointer = 0,
  329. IN ULONG_PTR Data = 0,
  330. IN BOOL fCaptureStackTrace = 0,
  331. IN int AdditionalFramesToSkip = 0
  332. );
  333. #ifdef RPC_LOGGING
  334. extern BOOL fEnableLog;
  335. inline void
  336. LogEvent(
  337. IN unsigned char Subject,
  338. IN unsigned char Verb,
  339. IN void * SubjectPointer,
  340. IN void * ObjectPointer = 0,
  341. IN ULONG_PTR Data = 0,
  342. IN BOOL fCaptureStackTrace = 0,
  343. IN int AdditionalFramesToSkip = 0
  344. )
  345. {
  346. if (fEnableLog)
  347. {
  348. TrulyLogEvent( Subject,
  349. Verb,
  350. SubjectPointer,
  351. ObjectPointer,
  352. Data,
  353. fCaptureStackTrace,
  354. AdditionalFramesToSkip
  355. );
  356. }
  357. }
  358. #else
  359. inline void
  360. LogEvent(
  361. IN unsigned char Subject,
  362. IN unsigned char Verb,
  363. IN void * SubjectPointer,
  364. IN void * ObjectPointer = 0,
  365. IN ULONG_PTR Data = 0,
  366. IN BOOL fCaptureStackTrace = 0,
  367. IN int AdditionalFramesToSkip = 0
  368. )
  369. {
  370. #if DBG
  371. TrulyLogEvent(Subject, Verb, SubjectPointer, ObjectPointer, Data, fCaptureStackTrace,
  372. AdditionalFramesToSkip);
  373. #endif
  374. }
  375. #endif
  376. //
  377. // LogError will produce an event even on normal retail builds.
  378. //
  379. #ifdef RPC_ERROR_LOGGING
  380. inline void
  381. LogError(
  382. IN unsigned char Subject,
  383. IN unsigned char Verb,
  384. IN void * SubjectPointer,
  385. IN void * ObjectPointer = 0,
  386. IN ULONG_PTR Data = 0,
  387. IN BOOL fCaptureStackTrace = 0,
  388. IN int AdditionalFramesToSkip = 0
  389. )
  390. {
  391. TrulyLogEvent( Subject,
  392. Verb,
  393. SubjectPointer,
  394. ObjectPointer,
  395. Data,
  396. fCaptureStackTrace,
  397. AdditionalFramesToSkip
  398. );
  399. }
  400. #else
  401. inline void
  402. LogError(
  403. IN unsigned char Subject,
  404. IN unsigned char Verb,
  405. IN void * SubjectPointer,
  406. IN void * ObjectPointer = 0,
  407. IN ULONG_PTR Data = 0,
  408. IN BOOL fCaptureStackTrace = 0,
  409. IN int AdditionalFramesToSkip = 0
  410. )
  411. {
  412. #if DBG
  413. TrulyLogEvent(Subject, Verb, SubjectPointer, ObjectPointer, Data, fCaptureStackTrace,
  414. AdditionalFramesToSkip);
  415. #endif
  416. }
  417. #endif
  418. #ifdef STATS
  419. extern DWORD g_dwStat1;
  420. extern DWORD g_dwStat2;
  421. extern DWORD g_dwStat3;
  422. extern DWORD g_dwStat4;
  423. inline void GetStats(DWORD *pdwStat1, DWORD *pdwStat2, DWORD *pdwStat3, DWORD *pdwStat4)
  424. {
  425. *pdwStat1 = g_dwStat1;
  426. *pdwStat2 = g_dwStat2;
  427. *pdwStat3 = g_dwStat3;
  428. *pdwStat4 = g_dwStat4;
  429. }
  430. inline void SetStat1(DWORD dwStat)
  431. {
  432. g_dwStat1 = dwStat;
  433. }
  434. inline void SetStat2(DWORD dwStat)
  435. {
  436. g_dwStat2 = dwStat;
  437. }
  438. inline void SetStat3(DWORD dwStat)
  439. {
  440. g_dwStat3 = dwStat;
  441. }
  442. inline void SetStat4(DWORD dwStat)
  443. {
  444. g_dwStat4 = dwStat;
  445. }
  446. inline void IncStat1(void)
  447. {
  448. InterlockedIncrement((long *) &g_dwStat1);
  449. }
  450. inline void DecStat1(void)
  451. {
  452. InterlockedDecrement((long *) &g_dwStat1);
  453. }
  454. inline void Stat1Add(long val)
  455. {
  456. InterlockedExchangeAdd((long *) &g_dwStat1, val);
  457. }
  458. inline void Stat1Sub(long val)
  459. {
  460. InterlockedExchangeAdd((long *) &g_dwStat1, -val);
  461. }
  462. inline void IncStat2(void)
  463. {
  464. InterlockedIncrement((long *) &g_dwStat2);
  465. }
  466. inline void DecStat2(void)
  467. {
  468. InterlockedDecrement((long *) &g_dwStat2);
  469. }
  470. inline void Stat2Add(long val)
  471. {
  472. InterlockedExchangeAdd((long *) &g_dwStat2, val);
  473. }
  474. inline void Stat2Sub(long val)
  475. {
  476. InterlockedExchangeAdd((long *) &g_dwStat2, -val);
  477. }
  478. inline void IncStat3(void)
  479. {
  480. InterlockedIncrement((long *) &g_dwStat3);
  481. }
  482. inline void DecStat3(void)
  483. {
  484. InterlockedDecrement((long *) &g_dwStat3);
  485. }
  486. inline void Stat3Add(long val)
  487. {
  488. InterlockedExchangeAdd((long *) &g_dwStat3, val);
  489. }
  490. inline void Stat3Sub(long val)
  491. {
  492. InterlockedExchangeAdd((long *) &g_dwStat3, -val);
  493. }
  494. inline void IncStat4(void)
  495. {
  496. InterlockedIncrement((long *) &g_dwStat4);
  497. }
  498. inline void DecStat4(void)
  499. {
  500. InterlockedDecrement((long *) &g_dwStat4);
  501. }
  502. inline void Stat4Add(long val)
  503. {
  504. InterlockedExchangeAdd((long *) &g_dwStat4, val);
  505. }
  506. inline void Stat4Sub(long val)
  507. {
  508. InterlockedExchangeAdd((long *) &g_dwStat4, -val);
  509. }
  510. #else
  511. inline void GetStats(DWORD *pdwStat1, DWORD *pdwStat2, DWORD *pdwStat3, DWORD *pdwStat4)
  512. {
  513. }
  514. inline void SetStat1(DWORD dwStat)
  515. {
  516. }
  517. inline void SetStat2(DWORD dwStat)
  518. {
  519. }
  520. inline void SetStat3(DWORD dwStat)
  521. {
  522. }
  523. inline void SetStat4(DWORD dwStat)
  524. {
  525. }
  526. inline void IncStat1(void)
  527. {
  528. }
  529. inline void DecStat1(void)
  530. {
  531. }
  532. inline void Stat1Add(long val)
  533. {
  534. }
  535. inline void Stat1Sub(long val)
  536. {
  537. }
  538. inline void IncStat2(void)
  539. {
  540. }
  541. inline void DecStat2(void)
  542. {
  543. }
  544. inline void Stat2Add(long val)
  545. {
  546. }
  547. inline void Stat2Sub(long val)
  548. {
  549. }
  550. inline void IncStat3(void)
  551. {
  552. }
  553. inline void DecStat3(void)
  554. {
  555. }
  556. inline void Stat3Add(long val)
  557. {
  558. }
  559. inline void Stat3Sub(long val)
  560. {
  561. }
  562. inline void IncStat4(void)
  563. {
  564. }
  565. inline void DecStat4(void)
  566. {
  567. }
  568. inline void Stat4Add(long val)
  569. {
  570. }
  571. inline void Stat4Sub(long val)
  572. {
  573. }
  574. #endif
  575. //
  576. // test hook data. The stuff that would logically live in UTIL.CXX is actually in DGCLNT.CXX
  577. // due to trouble linking the BVT programs.
  578. //
  579. typedef unsigned long RPC_TEST_HOOK_ID;
  580. typedef void (RPC_TEST_HOOK_FN_RAW)( RPC_TEST_HOOK_ID id, PVOID subject, PVOID object );
  581. typedef RPC_TEST_HOOK_FN_RAW * RPC_TEST_HOOK_FN;
  582. RPCRTAPI
  583. DWORD
  584. RPC_ENTRY
  585. I_RpcSetTestHook(
  586. RPC_TEST_HOOK_ID id,
  587. RPC_TEST_HOOK_FN fn
  588. );
  589. void
  590. ForceCallTestHook(
  591. RPC_TEST_HOOK_ID id,
  592. PVOID subject,
  593. PVOID object
  594. );
  595. //
  596. // ranges for the major field:
  597. //
  598. // common: 001-099
  599. // dg: 100-199
  600. // co: 200-299
  601. // lrpc: 300-399
  602. // transports: 400-499
  603. // reserved: 500-32767
  604. //
  605. #define MAKE_TEST_HOOK_ID( major, minor ) ( ((major) << 16) | (minor) )
  606. #define TH_RPC_BASE 1
  607. #define TH_DG_BASE 100
  608. #define TH_CO_BASE 200
  609. #define TH_LRPC_BASE 300
  610. #define TH_TRANS_BASE 400
  611. //
  612. // protocol-independent hook IDs.
  613. //
  614. // member functions of SECURITY_CONTEXT and SECURITY_CREDENTIALS
  615. //
  616. #define TH_SECURITY_PROVIDER (TH_RPC_BASE+1)
  617. //
  618. // Each of these hooks is passed the security context and a pStatus pointer.
  619. // If the hook makes *pStatus nonzero, that becomes the return code from the
  620. // member function.
  621. //
  622. #define TH_SECURITY_FN_SIGN MAKE_TEST_HOOK_ID( TH_SECURITY_PROVIDER, 1)
  623. #define TH_SECURITY_FN_VERIFY MAKE_TEST_HOOK_ID( TH_SECURITY_PROVIDER, 2)
  624. #define TH_SECURITY_FN_ACCEPT1 MAKE_TEST_HOOK_ID( TH_SECURITY_PROVIDER, 3)
  625. #define TH_SECURITY_FN_ACCEPT3 MAKE_TEST_HOOK_ID( TH_SECURITY_PROVIDER, 4)
  626. #define TH_SECURITY_FN_INIT1 MAKE_TEST_HOOK_ID( TH_SECURITY_PROVIDER, 5)
  627. #define TH_SECURITY_FN_INIT3 MAKE_TEST_HOOK_ID( TH_SECURITY_PROVIDER, 6)
  628. #define TH_RPC_SECURITY_SERVER_CONTEXT_CREATED MAKE_TEST_HOOK_ID( TH_SECURITY_PROVIDER, 7)
  629. #define TH_RPC_SECURITY_CLIENT_CONTEXT_CREATED MAKE_TEST_HOOK_ID( TH_SECURITY_PROVIDER, 8)
  630. // subject = pointer to RPC event structure
  631. // object = 0
  632. //
  633. #define TH_RPC_LOG_EVENT MAKE_TEST_HOOK_ID(TH_RPC_BASE+2, 1)
  634. inline void
  635. CallTestHook(
  636. RPC_TEST_HOOK_ID id,
  637. PVOID subject = 0,
  638. PVOID object = 0
  639. )
  640. {
  641. #ifdef RPC_ENABLE_TEST_HOOKS
  642. ForceCallTestHook( id, subject, object );
  643. #endif
  644. }
  645. #ifdef RPC_ENABLE_TEST_HOOKS
  646. RPC_TEST_HOOK_FN
  647. GetTestHook(
  648. RPC_TEST_HOOK_ID id
  649. );
  650. #endif
  651. #endif /* __UTIL_HXX__ */