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.

1014 lines
23 KiB

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <signal.h>
  4. #include <float.h>
  5. #include <time.h>
  6. #include <malloc.h>
  7. #include <stdlib.h>
  8. #include <math.h>
  9. static char Name[] = "Ken Reneris. Units ala Unix style";
  10. #define DBL double
  11. #define MAXTYPE 5
  12. extern UCHAR *UnitTab[];
  13. UCHAR token[] = " \t\n";
  14. typedef struct _UNIT {
  15. struct _UNIT *Next;
  16. PSZ UnitName;
  17. PSZ Conversion;
  18. } UNIT, *PUNIT;
  19. PUNIT UnitList;
  20. BOOLEAN Muund;
  21. typedef struct _HALFVALUE {
  22. DBL Accum;
  23. ULONG NoType;
  24. struct {
  25. PUNIT Unit;
  26. ULONG Pow;
  27. } Type [MAXTYPE];
  28. } HALFVALUE, *PHALFVALUE;
  29. typedef struct _FULLVALUE {
  30. ULONG Fuzz;
  31. HALFVALUE Nom;
  32. HALFVALUE Dom;
  33. } FULLVALUE, *PFULLVALUE;
  34. struct {
  35. PSZ Prefix;
  36. ULONG stringlen;
  37. DBL Scaler;
  38. } BuiltInScalers[] = {
  39. "giga", 4, 1000000000.0,
  40. "mega", 4, 1000000.0,
  41. "kilo", 4, 1000.0,
  42. "centi", 5, 0.01,
  43. "milli", 5, 0.001,
  44. "micro", 5, 0.000001,
  45. "nano", 4, 0.000000001,
  46. "decinano", 8, 0.0000000001,
  47. NULL
  48. };
  49. struct {
  50. PSZ BaseType;
  51. PSZ DefaultDump;
  52. } BuiltInDumps[] = {
  53. "sec", "hour second millisec microsec nttime nanosec",
  54. "bit", "terabyte gigabyte megabyte kilobyte dword byte bit",
  55. "meter", "km meter cm mm micron mile feet yard inch",
  56. "kg", "kb gram kilokg milligram ton lb ounce dram",
  57. NULL
  58. };
  59. #define ASSERT(_exp_) if (_exp_) { AssertFailed (__FILE__, __LINE__); }
  60. PVOID zalloc (IN ULONG len);
  61. PSZ StrDup (IN PSZ String);
  62. VOID ReadUnitTab (VOID);
  63. PUNIT LookupUnit (PSZ UnitName);
  64. VOID DumpValue (IN PFULLVALUE Value);
  65. VOID InitializeValue (IN PFULLVALUE Value);
  66. VOID ConvertValue (PFULLVALUE, PSZ, PFULLVALUE, PSZ);
  67. BOOLEAN ProcessString (PUNIT, PSZ, PFULLVALUE);
  68. PSZ CopyUnitName (PSZ Out, PSZ String);
  69. PSZ CopyWord (PSZ Out, PSZ String);
  70. PSZ SkipSpace (PSZ String);
  71. BOOLEAN MatchPattern (PUCHAR String, PUCHAR Pattern);
  72. VOID ReduceTypes (IN OUT PHALFVALUE MValue, IN OUT PHALFVALUE DValue);
  73. VOID AddTypes (IN OUT PHALFVALUE Dest, IN PHALFVALUE Child);
  74. BOOLEAN DumpMatchingTypes (PSZ Str);
  75. VOID GetInput (PSZ Desc, PSZ Str);
  76. VOID AssertFailed (PSZ FileName, ULONG LineNo);
  77. void __cdecl main(int argc, char **argv)
  78. {
  79. UCHAR have[80], want[80], want2[200];
  80. FULLVALUE hValue, wValue;
  81. PSZ p;
  82. ULONG i;
  83. ReadUnitTab ();
  84. if (argc > 1) {
  85. //
  86. // Arguments on the command line. Argv[1] is "have"
  87. //
  88. argv++;
  89. argc -= 2;
  90. strcpy (have, *(argv++));
  91. if (DumpMatchingTypes (have)) {
  92. exit (0);
  93. }
  94. if (!ProcessString (NULL, have, &hValue)) {
  95. printf ("Usage: Units [have] [want]\n");
  96. exit (1);
  97. }
  98. //
  99. // If no Argv[2], then check for default dump
  100. //
  101. if (!argc && hValue.Nom.NoType) {
  102. for (i=0; BuiltInDumps[i].BaseType; i++) {
  103. if (strcmp (BuiltInDumps[i].BaseType, hValue.Nom.Type[0].Unit->UnitName) == 0) {
  104. //
  105. // Dump defaults
  106. //
  107. p = BuiltInDumps[i].DefaultDump;
  108. while (*p) {
  109. p = CopyWord(want, p);
  110. if (ProcessString (NULL, want, &wValue)) {
  111. ConvertValue (&hValue, have, &wValue, want);
  112. }
  113. }
  114. break;
  115. }
  116. }
  117. }
  118. //
  119. // Dump argv[2..n]
  120. //
  121. for ( ; argc; argc--, argv++) {
  122. if (!ProcessString (NULL, *argv, &wValue)) {
  123. exit (1);
  124. }
  125. ConvertValue (&hValue, have, &wValue, *argv);
  126. }
  127. exit (1);
  128. }
  129. //
  130. // Interactive... ask "have" & "want"
  131. //
  132. for (; ;) {
  133. for (; ;) {
  134. GetInput ("You have: ", have);
  135. if (ProcessString (NULL, have, &hValue)) {
  136. break;
  137. }
  138. }
  139. GetInput ("You want: ", want2);
  140. p = want2;
  141. do {
  142. p = CopyWord (want, p);
  143. if (ProcessString (NULL, want, &wValue)) {
  144. ConvertValue (&hValue, have, &wValue, want);
  145. }
  146. } while (*p);
  147. printf ("\n");
  148. }
  149. return ;
  150. }
  151. VOID
  152. GetInput (
  153. PSZ Desc,
  154. PSZ Str
  155. )
  156. {
  157. for (; ;) {
  158. printf (Desc);
  159. if (!gets(Str)) {
  160. exit(1);
  161. }
  162. _strlwr (Str);
  163. if (strcmp (Str, "q") == 0) {
  164. exit (1);
  165. }
  166. if (!DumpMatchingTypes (Str)) {
  167. break;
  168. }
  169. }
  170. }
  171. BOOLEAN DumpMatchingTypes (PSZ Str)
  172. {
  173. PSZ Title, Line;
  174. ULONG LineNo;
  175. UCHAR UnitName[80];
  176. BOOLEAN DumpTitle;
  177. if (!strchr (Str, '*') && !strchr (Str, '?') && !strchr(Str, '[')) {
  178. return FALSE;
  179. }
  180. //
  181. // Dump matching known unitnames
  182. //
  183. printf ("\nKnown types/groups matching: %s\n", Str);
  184. Title = NULL;
  185. for (LineNo = 0; UnitTab[LineNo]; LineNo++) {
  186. Line = UnitTab[LineNo];
  187. if (Line[0] == '/') {
  188. Title = Line;
  189. DumpTitle = MatchPattern (Title, Str);
  190. }
  191. CopyUnitName (UnitName, Line);
  192. if (!UnitName[0]) {
  193. continue;
  194. }
  195. if (MatchPattern (UnitName, Str) || DumpTitle) {
  196. if (Title) {
  197. printf ("%s\n", Title);
  198. Title = NULL;
  199. }
  200. printf (" %s\n", Line);
  201. }
  202. }
  203. printf ("\n");
  204. return TRUE;
  205. }
  206. PSZ SkipSpace (PSZ String)
  207. {
  208. while (*String && (*String == ' ' || *String < ' ' || *String == '^')) {
  209. String ++;
  210. }
  211. return String;
  212. }
  213. PSZ CopyNumber (PSZ Out, PSZ String)
  214. {
  215. while (*String >= '0' && *String <= '9' || *String == '.') {
  216. *(Out++) = *(String++);
  217. }
  218. *Out = 0;
  219. return String;
  220. }
  221. PSZ CopyWord (PSZ Out, PSZ String)
  222. {
  223. UCHAR c;
  224. while (*String) {
  225. if (*String <= ' ') {
  226. break;
  227. }
  228. *(Out++) = *(String++);
  229. }
  230. *Out = 0;
  231. return SkipSpace (String);
  232. }
  233. PSZ CopyUnitName (PSZ Out, PSZ String)
  234. {
  235. UCHAR c;
  236. while (c = *String) {
  237. if (c >= '0' && c <= '9' || c == '.') {
  238. break;
  239. }
  240. if (c == '-' || c == '+' || c == '/' || c == ' ') {
  241. break;
  242. }
  243. if (c == '^' || c < ' ') {
  244. String++;
  245. continue;
  246. }
  247. *(Out++) = *(String++);
  248. }
  249. *Out = 0;
  250. return String;
  251. }
  252. VOID
  253. AssertFailed (PSZ FileName, ULONG LineNo)
  254. {
  255. printf ("Assert failed - file %s line %d\n", FileName, LineNo);
  256. exit (1);
  257. }
  258. PSZ
  259. GetBaseType (
  260. IN PSZ Out,
  261. IN PHALFVALUE HValue
  262. )
  263. {
  264. ULONG i;
  265. if (HValue->NoType == 0) {
  266. Out += sprintf (Out, "constant");
  267. } else {
  268. for (i=0; i < HValue->NoType; i++) {
  269. Out += sprintf (Out, "%s%s", i ? "-" : "", HValue->Type[i].Unit->UnitName);
  270. if (HValue->Type[i].Pow != 1) {
  271. Out += sprintf (Out, "^%d", HValue->Type[i].Pow);
  272. }
  273. }
  274. }
  275. return Out;
  276. }
  277. VOID
  278. GetBaseTypes (
  279. OUT PSZ Out,
  280. IN PFULLVALUE Value
  281. )
  282. /**
  283. * Returns ascii dump of values data type
  284. */
  285. {
  286. PUNIT Unit;
  287. ULONG i;
  288. Out = GetBaseType (Out, &Value->Nom);
  289. if (Value->Dom.NoType) {
  290. Out += sprintf (Out, "/");
  291. Out = GetBaseType (Out, &Value->Dom);
  292. }
  293. }
  294. VOID
  295. DumpValue (
  296. IN PFULLVALUE Value
  297. )
  298. {
  299. UCHAR s[80];
  300. GetBaseTypes (s, Value);
  301. printf ("%g/%g type %s\n", Value->Nom.Accum, Value->Dom.Accum, s);
  302. }
  303. VOID
  304. SortType (
  305. IN PHALFVALUE Value
  306. )
  307. {
  308. ULONG i, j;
  309. ULONG hpow;
  310. PUNIT hunit;
  311. //
  312. // Sort by lowest power, then alphabetical
  313. //
  314. for (i=0; i < Value->NoType; i++) {
  315. for (j=i+1; j < Value->NoType; j++) {
  316. if (Value->Type[i].Pow > Value->Type[j].Pow ||
  317. (Value->Type[i].Pow == Value->Type[j].Pow &&
  318. strcmp (Value->Type[i].Unit->UnitName, Value->Type[j].Unit->UnitName) > 0)) {
  319. // swap
  320. hpow = Value->Type[i].Pow;
  321. hunit = Value->Type[i].Unit;
  322. Value->Type[i].Pow = Value->Type[j].Pow;
  323. Value->Type[i].Unit = Value->Type[j].Unit;
  324. Value->Type[j].Pow = hpow;
  325. Value->Type[j].Unit = hunit;
  326. }
  327. }
  328. }
  329. }
  330. VOID
  331. FormatDbl (
  332. OUT PSZ s,
  333. IN DBL Value
  334. )
  335. /**
  336. * Function to print double "Value" into string "s". This
  337. * functions sole purpose is to get a better readable reresentation
  338. * of the value into ascii
  339. */
  340. {
  341. PSZ p1, p2, dp;
  342. UCHAR t[80];
  343. LONG i;
  344. i = 18 - sprintf (t, "%.1f", Value);
  345. if (i < 0) {
  346. i = 0;
  347. }
  348. sprintf (t, "%.*f", i, Value);
  349. //
  350. // strip off trailing zeros
  351. //
  352. for (dp=t; *dp; dp++) {
  353. if (*dp == '.') {
  354. for (p1=p2=dp+1; *p2; p2++) {
  355. if (*p2 != '0') {
  356. p1 = p2;
  357. }
  358. }
  359. p1[1] = 0;
  360. if (p1 == dp+1 && p1[0] == '0') {
  361. // it's ".0" remove the whole thing
  362. *dp = 0;
  363. }
  364. break;
  365. }
  366. }
  367. i = (LONG)(dp - t); // # of digits before decimal point
  368. i = i % 3;
  369. if (i == 0) {
  370. i = 3;
  371. }
  372. //
  373. // Copy to decimal point while adding commas
  374. //
  375. for (p1=s, p2=t; *p2 && *p2 != '.'; p2++) {
  376. if (i-- == 0) {
  377. *(p1++) = ',';
  378. i = 2;
  379. }
  380. *(p1++) = *p2;
  381. }
  382. //
  383. // Copy remainer
  384. //
  385. do {
  386. *(p1++) = *p2;
  387. } while (*(p2++));
  388. //
  389. // Did result == 0? Probabily lost precision
  390. //
  391. if (strcmp (s, "0") == 0) {
  392. sprintf (s, "%.18g", Value);
  393. }
  394. }
  395. VOID
  396. ConvertValue (
  397. IN PFULLVALUE hValue,
  398. IN PSZ have,
  399. IN PFULLVALUE wValue,
  400. IN PSZ want
  401. )
  402. {
  403. DBL ans;
  404. UCHAR s1[80], s2[80], cf[80];
  405. FULLVALUE Junk1, Junk2;
  406. BOOLEAN flag;
  407. DBL hAccum, wAccum;
  408. PSZ p1, p2, p3, p4, p5;
  409. have = SkipSpace(have);
  410. want = SkipSpace(want);
  411. hAccum = hValue->Nom.Accum / hValue->Dom.Accum;
  412. wAccum = wValue->Nom.Accum / wValue->Dom.Accum;
  413. ans = hAccum / wAccum;
  414. p3 = "";
  415. p5 = NULL;
  416. //
  417. // See if types match by checking if they cancle each other out
  418. //
  419. Junk1 = *hValue;
  420. Junk2 = *wValue;
  421. AddTypes (&Junk1.Nom, &Junk2.Dom);
  422. AddTypes (&Junk1.Dom, &Junk2.Nom);
  423. ReduceTypes (&Junk1.Nom, &Junk1.Dom);
  424. if (Junk1.Nom.NoType + Junk1.Dom.NoType != 0) {
  425. //
  426. // See if types are inverse
  427. //
  428. Junk1 = *hValue;
  429. Junk2 = *wValue;
  430. AddTypes (&Junk1.Nom, &Junk2.Nom);
  431. AddTypes (&Junk1.Dom, &Junk2.Dom);
  432. ReduceTypes (&Junk1.Nom, &Junk1.Dom);
  433. if (Junk1.Nom.NoType + Junk1.Dom.NoType == 0) {
  434. // inverse result
  435. ans = 1.0 / (hAccum / (1.0 / wAccum));
  436. p5 = "Warning";
  437. } else {
  438. // types are not conforming
  439. p5 = "Conformance";
  440. }
  441. }
  442. cf[0] = 0;
  443. if (p5) {
  444. SortType (&hValue->Nom);
  445. SortType (&hValue->Dom);
  446. SortType (&wValue->Nom);
  447. SortType (&wValue->Dom);
  448. GetBaseTypes (s1, hValue);
  449. GetBaseTypes (s2, wValue);
  450. sprintf (cf, " (%s: %s -> %s)", p5, s1, s2);
  451. }
  452. FormatDbl (s1, ans); // fancy
  453. sprintf (s2, "%.g", ans); // bland
  454. p1 = (have[0] >= 'a' && have[0] <= 'z') ? "1" : "";
  455. p2 = (hValue->Fuzz | wValue->Fuzz) ? "(fuzzy) " : "",
  456. printf (" %s%s -> %s %s%s%s%s\n", p1, have, s1, p2, p3, want, cf);
  457. p4 = strchr (s2, 'e');
  458. if (p4 && !strchr(s1,'e') && atoi(p4+2) > 9) {
  459. // print bland answer as well
  460. printf (" %s%s -> %s %s%s%s%s\n", p1, have, s2, p2, p3, want, cf);
  461. }
  462. }
  463. BOOLEAN
  464. ProcessString (
  465. IN PUNIT Unit,
  466. IN PSZ String,
  467. OUT PFULLVALUE ReturnValue
  468. )
  469. {
  470. UCHAR s[80], c;
  471. ULONG i, j;
  472. FULLVALUE ChildValue;
  473. PHALFVALUE MValue, DValue, hldvalue;
  474. ReturnValue->Fuzz = 0;
  475. MValue = &ReturnValue->Nom;
  476. DValue = &ReturnValue->Dom;
  477. MValue->Accum = 1.0;
  478. MValue->NoType = 0;
  479. DValue->Accum = 1.0;
  480. DValue->NoType = 0;
  481. String = SkipSpace(String);
  482. c = *String;
  483. if (c == '*') {
  484. //
  485. // This is a base value
  486. //
  487. MValue->NoType = 1;
  488. MValue->Type[0].Unit = Unit;
  489. MValue->Type[0].Pow = 1;
  490. return TRUE;
  491. }
  492. if (c >= '0' && c <= '9' || c == '.') {
  493. //
  494. // Constant multiplcation
  495. //
  496. String = CopyNumber (s, String);
  497. String = SkipSpace(String);
  498. MValue->Accum *= atof(s);
  499. }
  500. if (*String == '|') {
  501. //
  502. // Constant Division
  503. //
  504. String++;
  505. String = CopyNumber (s, String);
  506. if (s[0]) {
  507. DValue->Accum *= atof(s);
  508. }
  509. }
  510. if (*String == '+' || *String == '-') {
  511. //
  512. // 10^x
  513. //
  514. s[0] = *(String++);
  515. String = CopyNumber (s+1, String);
  516. MValue->Accum *= pow (10.0, atof(s));
  517. }
  518. for (; ;) {
  519. String = SkipSpace(String);
  520. if (!*String) {
  521. break;
  522. }
  523. switch (*String) {
  524. case '/':
  525. // flip denominator & numerator
  526. hldvalue = MValue;
  527. MValue = DValue;
  528. DValue = hldvalue;
  529. String++;
  530. continue; // get next token
  531. case '-':
  532. // skip these
  533. String++;
  534. continue;
  535. default:
  536. break;
  537. }
  538. //
  539. // Find sub unit type
  540. //
  541. String = CopyUnitName (s, String);
  542. Unit = LookupUnit (s);
  543. if (!Unit) {
  544. //
  545. // Check for common scaler prefix on keyword
  546. //
  547. for (i=0; BuiltInScalers[i].Prefix; i++) {
  548. if (strncmp (s,
  549. BuiltInScalers[i].Prefix,
  550. BuiltInScalers[i].stringlen) == 0) {
  551. // Scale the value & skip word prefix
  552. MValue->Accum *= BuiltInScalers[i].Scaler;
  553. Unit = LookupUnit (s + BuiltInScalers[i].stringlen);
  554. break;
  555. }
  556. }
  557. if (!Unit) {
  558. printf ("Unit type '%s' unkown\n", s);
  559. return FALSE;
  560. }
  561. }
  562. //
  563. // Get conversion value for this component
  564. //
  565. if (!ProcessString (Unit, Unit->Conversion, &ChildValue)) {
  566. return FALSE;
  567. }
  568. if (strcmp (Unit->UnitName, "fuzz") == 0) {
  569. ReturnValue->Fuzz = 1;
  570. }
  571. if (*String >= '1' && *String <= '9') {
  572. // raise power
  573. i = *(String++) - '0';
  574. ChildValue.Nom.Accum = pow (ChildValue.Nom.Accum, i);
  575. ChildValue.Dom.Accum = pow (ChildValue.Dom.Accum, i);
  576. for (j=0; j < ChildValue.Nom.NoType; j++) {
  577. ChildValue.Nom.Type[j].Pow *= i;
  578. }
  579. for (j=0; j < ChildValue.Dom.NoType; j++) {
  580. ChildValue.Dom.Type[i].Pow *= i;
  581. }
  582. }
  583. //
  584. // Merge values from child
  585. //
  586. ReturnValue->Fuzz |= ChildValue.Fuzz;
  587. MValue->Accum *= ChildValue.Nom.Accum;
  588. DValue->Accum *= ChildValue.Dom.Accum;
  589. //
  590. // Merge data types from child
  591. //
  592. AddTypes (MValue, &ChildValue.Nom);
  593. AddTypes (DValue, &ChildValue.Dom);
  594. ReduceTypes (MValue, DValue);
  595. }
  596. return TRUE;
  597. }
  598. VOID
  599. AddTypes (
  600. IN OUT PHALFVALUE Dest,
  601. IN PHALFVALUE Child
  602. )
  603. /**
  604. * Add's types from Child to Dest. If the data type already exist in
  605. * dest then it's power is raised; otherwise the new type is added to the list
  606. *
  607. */
  608. {
  609. ULONG i, j;
  610. for (i=0; i < Child->NoType; i++) {
  611. for (j=0; j < Dest->NoType; j++) {
  612. if (Child->Type[i].Unit == Dest->Type[j].Unit) {
  613. // unit already is destionation - move it
  614. Dest->Type[j].Pow += Child->Type[i].Pow;
  615. Child->Type[i].Unit = NULL;
  616. Child->Type[i].Pow = 0;
  617. }
  618. }
  619. if (Child->Type[i].Unit) {
  620. // unit not in destionation - add it
  621. j = (Dest->NoType++);
  622. ASSERT (j >= MAXTYPE);
  623. Dest->Type[j].Unit = Child->Type[i].Unit;
  624. Dest->Type[j].Pow = Child->Type[i].Pow;
  625. }
  626. }
  627. }
  628. VOID
  629. ReduceTypes (
  630. IN OUT PHALFVALUE MValue,
  631. IN OUT PHALFVALUE DValue
  632. )
  633. /**
  634. * Divides & cancles data types.
  635. */
  636. {
  637. ULONG i, j, k;
  638. BOOLEAN Restart;
  639. Restart = TRUE;
  640. while (Restart) {
  641. Restart = FALSE;
  642. for (i=0; i < MValue->NoType; i++) {
  643. for (j=0; j < DValue->NoType; j++) {
  644. if (MValue->Type[i].Unit == DValue->Type[j].Unit) {
  645. // matching types - reduce
  646. MValue->Type[i].Pow -= DValue->Type[j].Pow;
  647. DValue->Type[j].Unit = NULL;
  648. DValue->Type[j].Pow = 0;
  649. }
  650. if (DValue->Type[j].Pow == 0) {
  651. // pull this type out of the denominator
  652. for (k=j+1; k < DValue->NoType; k++) {
  653. DValue->Type[k-1] = DValue->Type[k];
  654. }
  655. DValue->NoType -= 1;
  656. Restart = TRUE;
  657. continue;
  658. }
  659. }
  660. if (MValue->Type[i].Pow == 0) {
  661. // pull this type out of the numerator
  662. for (k=i+1; k < DValue->NoType; k++) {
  663. DValue->Type[k-1] = DValue->Type[k];
  664. }
  665. MValue->NoType -= 1;
  666. Restart = TRUE;
  667. continue;
  668. }
  669. }
  670. }
  671. }
  672. VOID
  673. ReadUnitTab (VOID)
  674. {
  675. UCHAR Line[80], s[80];
  676. ULONG LineNo;
  677. PUNIT Unit;
  678. PSZ p, p1;
  679. for (LineNo = 0; UnitTab[LineNo]; LineNo++) {
  680. strcpy (Line, UnitTab[LineNo]);
  681. //
  682. // Strip off trailing blanks
  683. //
  684. for (p=p1=Line; *p; p++) {
  685. if (*p != ' ') {
  686. p1 = p;
  687. }
  688. }
  689. p1[1] = 0;
  690. //
  691. // First word is type of unit
  692. //
  693. p = SkipSpace (Line);
  694. if (*p == 0 || *p == '/') {
  695. continue;
  696. }
  697. p = CopyUnitName (s, p);
  698. Unit = zalloc (sizeof(UNIT));
  699. Unit->UnitName = StrDup (s);
  700. //
  701. // Rest of line is Conversion string
  702. //
  703. p = SkipSpace (p);
  704. Unit->Conversion = StrDup (p);
  705. //
  706. // Add Unit to list of all known units
  707. //
  708. Unit->Next = UnitList;
  709. UnitList = Unit;
  710. }
  711. }
  712. PUNIT LookupUnit (PSZ UnitName)
  713. {
  714. PUNIT Unit;
  715. UCHAR Name[40];
  716. ULONG i;
  717. for (i=0; UnitName[i]; i++) {
  718. Name[i] = UnitName[i];
  719. if (Name[i] >= '0' && Name[i] <= '9') {
  720. break;
  721. }
  722. }
  723. Name[i] = 0;
  724. for (Unit=UnitList; Unit; Unit = Unit->Next) {
  725. if (strcmp (Unit->UnitName, Name) == 0) {
  726. break;
  727. }
  728. }
  729. return Unit;
  730. }
  731. PSZ StrDup (IN PSZ String)
  732. {
  733. ULONG len;
  734. PSZ p;
  735. // allocate & duplicate string
  736. len = strlen(String)+1;
  737. p = malloc (len);
  738. if (!p) {
  739. printf ("Out of memory\n");
  740. exit (1);
  741. }
  742. memcpy (p, String, len);
  743. return p;
  744. }
  745. PVOID zalloc (IN ULONG len)
  746. {
  747. PVOID p;
  748. // allocate & zero memory
  749. p = malloc (len);
  750. if (!p) {
  751. printf ("Out of memory\n");
  752. exit (1);
  753. }
  754. memset (p, 0, len);
  755. return p;
  756. }
  757. /*** MatchPattern - check if string matches pattern
  758. *
  759. * Supports:
  760. * * - Matches any number of characters (including zero)
  761. * ? - Matches any 1 character
  762. * [set] - Matches any charater to charater in set
  763. * (set can be a list or range)
  764. *
  765. */
  766. BOOLEAN MatchPattern (PUCHAR String, PUCHAR Pattern)
  767. {
  768. UCHAR c, p, l;
  769. for (; ;) {
  770. switch (p = *Pattern++) {
  771. case 0: // end of pattern
  772. return *String ? FALSE : TRUE; // if end of string TRUE
  773. case '*':
  774. while (*String) { // match zero or more char
  775. if (MatchPattern (String++, Pattern))
  776. return TRUE;
  777. }
  778. return MatchPattern (String, Pattern);
  779. case '?':
  780. if (*String++ == 0) // match any one char
  781. return FALSE; // not end of string
  782. break;
  783. case '[':
  784. if ( (c = *String++) == 0) // match char set
  785. return FALSE; // syntax
  786. c = (UCHAR)tolower(c);
  787. l = 0;
  788. while (p = *Pattern++) {
  789. if (p == ']') // if end of char set, then
  790. return FALSE; // no match found
  791. if (p == '-') { // check a range of chars?
  792. p = *Pattern; // get high limit of range
  793. if (p == 0 || p == ']')
  794. return FALSE; // syntax
  795. if (c >= l && c <= p)
  796. break; // if in range, move on
  797. }
  798. l = p;
  799. if (c == p) // if char matches this element
  800. break; // move on
  801. }
  802. while (p && p != ']') // got a match in char set
  803. p = *Pattern++; // skip to end of set
  804. break;
  805. default:
  806. c = *String++;
  807. if (tolower(c) != p) // check for exact char
  808. return FALSE; // not a match
  809. break;
  810. }
  811. }
  812. }