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.

477 lines
12 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. tpl.cpp
  5. Abstract:
  6. template file interpreter for tracewpp.exe
  7. Author:
  8. Gor Nishanov (gorn) 03-Apr-1999
  9. Revision History:
  10. Gor Nishanov (gorn) 03-Apr-1999 -- hacked together to prove that this can work
  11. GorN: 29-Sep-2000 - fix WHERE clause handling
  12. ToDo:
  13. Clean it up
  14. --*/
  15. #define UNICODE
  16. #include <stdio.h>
  17. #include <windows.h>
  18. #pragma warning(disable: 4786)
  19. #pragma warning(disable: 4503) // decorated length
  20. #pragma warning(disable: 4512) // cannot generate assignment
  21. #pragma warning(disable: 4100) // '_P' : unreferenced formal parameter
  22. #pragma warning(disable: 4018) // signed/unsigned mismatch
  23. #pragma warning(disable: 4267) // 'return' : conversion from 'size_t' to 'int'
  24. #include <xmemory>
  25. #include <xstring>
  26. #include <set>
  27. #include <map>
  28. #pragma warning(disable: 4663 4018)
  29. #include <vector>
  30. //#pragma warning(default: 4018 4663) // signed/unsigned mismatch
  31. #pragma warning(default: 4100)
  32. #include "ezparse.h"
  33. #include "fieldtable.h"
  34. #include "tpl.h"
  35. LPCSTR FieldNames[] = {
  36. #define FIELD_NAME(f) #f,
  37. INSERT_FIELD_NAMES
  38. #undef FIELD_NAME
  39. };
  40. OBJECT_MAP ObjectMap;
  41. typedef std::map<std::string, FieldId, strless> FIELD_MAP;
  42. FIELD_MAP FieldMap;
  43. void PopulateFieldMap() {
  44. #define FIELD_NAME(_name_) FieldMap[#_name_] = fid_ ## _name_;
  45. INSERT_FIELD_NAMES
  46. #undef FIELD_NAME
  47. FIELD_MAP::iterator i;
  48. }
  49. ////////////////////////////////////////////////////////////////////////////////////////////
  50. struct LoopVar : FieldHolder {
  51. Enumerator * Enum;
  52. std::string Name;
  53. LoopVar() {}
  54. DWORD PrintField(int fieldId, FILE* f, const Enumerator** pEnum) const {
  55. return Enum->GetData()->PrintField(fieldId, f, pEnum);
  56. }
  57. };
  58. ///////////////////////////////////////////////////////////////////////////////////////////
  59. char Delimiter = '`';
  60. std::string COMMENT("*");
  61. std::string FORALL("FORALL");
  62. std::string ENDFOR("ENDFOR");
  63. std::string IF("IF");
  64. std::string ENDIF("ENDIF");
  65. std::string DELIMITER("DELIMITER");
  66. std::string INCLUDE("INCLUDE");
  67. std::string ENV("ENV");
  68. typedef enum Action {
  69. actText,
  70. actVar,
  71. actLoop,
  72. actIf,
  73. actInclude,
  74. actLiteralString,
  75. } Action;
  76. #pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union
  77. struct Chunk {
  78. struct {
  79. Action action : 8;
  80. UCHAR level : 8;
  81. SHORT loopEnd:16;
  82. };
  83. union {
  84. struct {
  85. LPCSTR textBeg;
  86. LPCSTR textEnd;
  87. };
  88. struct {
  89. FieldHolder * p;
  90. FieldId FieldNo;
  91. std::string Filter;
  92. };
  93. };
  94. Enumerator* getEnum() {
  95. const Enumerator* Enum; p->PrintField(FieldNo, 0, &Enum); return (Enumerator*)Enum; }
  96. void printField(FILE* out) const {
  97. p->PrintField(FieldNo, out, 0); }
  98. Chunk(){} // to make vector happy
  99. Chunk (Action Act, FieldHolder* fh, FieldId fid, int lvl, const std::string& filter):
  100. action(Act),FieldNo(fid),p(fh),level((UCHAR)lvl),Filter(filter) {}
  101. Chunk (FieldHolder* fh, FieldId fid):action(actVar),FieldNo(fid),p(fh) {}
  102. Chunk (LPCSTR b, LPCSTR e):action(actText),textBeg(b),textEnd(e) {}
  103. Chunk (Action act, LPCSTR b, LPCSTR e):action(act),textBeg(b),textEnd(e) {}
  104. explicit Chunk(std::string const& Text):action(actLiteralString),Filter(Text) {}
  105. };
  106. #define MAX_LOOP_LEVEL 127
  107. struct TemplateProcessor {
  108. LoopVar Loop[MAX_LOOP_LEVEL];
  109. std::vector<Chunk> Chunks;
  110. void RunIt(int beg, int end, FILE* out) {
  111. for(int i = beg; i < end; ) {
  112. switch(Chunks[i].action) {
  113. case actLiteralString:
  114. {
  115. fwrite(Chunks[i].Filter.c_str(), Chunks[i].Filter.length(), 1, out );
  116. ++i;
  117. break;
  118. }
  119. case actText:
  120. {
  121. for(LPCSTR p = Chunks[i].textBeg; p < Chunks[i].textEnd; ++p) {
  122. if (*p != '\r') putc(*p, out);
  123. }
  124. ++i;
  125. break;
  126. }
  127. case actVar:
  128. {
  129. Chunks[i].printField(out);
  130. ++i;
  131. break;
  132. }
  133. case actIf:
  134. {
  135. if (!Chunks[i].p->Hidden(Chunks[i].Filter)) {
  136. RunIt(i+1, Chunks[i].loopEnd, out);
  137. }
  138. i = Chunks[i].loopEnd;
  139. break;
  140. }
  141. case actLoop:
  142. {
  143. Enumerator * Enum = Chunks[i].getEnum();
  144. Loop[Chunks[i].level].Enum = Enum;
  145. for(Enum->Reset(Chunks[i].Filter); Enum->Valid(); Enum->Next(Chunks[i].Filter) ) {
  146. RunIt(i+1, Chunks[i].loopEnd, out);
  147. }
  148. delete Enum;
  149. i = Chunks[i].loopEnd;
  150. break;
  151. }
  152. case actInclude:
  153. {
  154. ProcessTemplate(Chunks[i].textBeg, Chunks[i].textEnd, out);
  155. ++i;
  156. break;
  157. }
  158. }
  159. }
  160. }
  161. void DoId(LPCSTR q, LPCSTR p, FieldId& fid, FieldHolder*& fh)
  162. {
  163. LPCSTR dot = q;
  164. while (q < p && isspace(*q)) ++q;
  165. while (q < p && isspace(p[-1])) --p;
  166. while (dot < p && *dot != '.') ++dot;
  167. std::string ObjectName(q, dot);
  168. OBJECT_MAP::iterator it = ObjectMap.find( ObjectName );
  169. if (it == ObjectMap.end()) {
  170. ReportError("Var not found: %s\n", ObjectName.c_str() );
  171. exit(1);
  172. } else {
  173. std::string FieldName;
  174. if (dot == p) {
  175. fid = (FieldId)fid___default__;
  176. FieldName.assign("__default__");
  177. } else {
  178. ++dot;
  179. while (p < dot && isspace(*dot)) ++dot;
  180. FieldName.assign(dot,p);
  181. FIELD_MAP::iterator fit = FieldMap.find( FieldName.c_str() );
  182. if (fit == FieldMap.end()) {
  183. ReportError("FieldNotFound: %s.%s\n", ObjectName.c_str(), FieldName.c_str() );
  184. exit(1);
  185. } else {
  186. fid = fit->second;
  187. }
  188. }
  189. }
  190. fh = it->second;
  191. }
  192. void DoVar(LPCSTR q, LPCSTR p) {
  193. FieldHolder* fh;
  194. FieldId fid;
  195. DoId(q,p, fid, fh);
  196. Chunks.push_back( Chunk(fh, fid) );
  197. }
  198. void DoLoop(int loopLevel, LPCSTR beg, LPCSTR end) {
  199. FieldHolder* fh;
  200. FieldId fid;
  201. std::string LoopVar;
  202. std::string LoopSet;
  203. std::string Filter;
  204. LPCSTR p,q;
  205. p = beg+6; while (p < end && isspace(*p)) ++p;
  206. q = p; while(p < end && !isspace(*p)) ++p;
  207. LoopVar.assign(q,p);
  208. Loop[loopLevel].Name = LoopVar;
  209. p += 4; while (p < end && isspace(*p)) ++p;
  210. q = p; while(p < end && !isspace(*p)) ++p;
  211. DoId(q,p, fid, fh);
  212. LoopSet.assign(q, p);
  213. p += 7; while (p < end && isspace(*p)) ++p;
  214. q = p;
  215. if (q < end) {
  216. p = end; while(p > q && isspace(*--p));
  217. if (p < end && !isspace(*p)) ++p;
  218. }
  219. Filter.assign(q,p);
  220. Flood("FORALL %s IN %s WHERE %s\n", LoopVar.c_str(), LoopSet.c_str(),
  221. Filter.c_str());
  222. ObjectMap[LoopVar] = &Loop[loopLevel];
  223. Chunks.push_back( Chunk(actLoop, fh, fid, loopLevel, Filter) );
  224. }
  225. void DoIf(int loopLevel, LPCSTR beg, LPCSTR end) {
  226. FieldHolder* fh;
  227. FieldId fid;
  228. std::string Object;
  229. std::string Filter;
  230. LPCSTR p,q;
  231. p = beg+3; while (p < end && isspace(*p)) ++p;
  232. q = p; while(p < end && !isspace(*p)) ++p;
  233. DoId(q,p, fid, fh); // Split id //
  234. Object.assign(q, p);
  235. while (p < end && isspace(*p)) ++p;
  236. while (p < end && isspace(end[-1]) ) --end;
  237. Filter.assign(p,end);
  238. Flood("IF %s %s\n", Object.c_str(), Filter.c_str() );
  239. Chunks.push_back( Chunk(actIf, fh, fid, loopLevel, Filter) );
  240. }
  241. DWORD
  242. CompileAndRun(
  243. IN LPCSTR begin,
  244. IN LPCSTR end,
  245. IN FILE* out
  246. )
  247. {
  248. LPCSTR p = begin, PlainText = begin;
  249. int loop = -1;
  250. int loopLevel = -1;
  251. bool comment;
  252. Chunks.erase(Chunks.begin(), Chunks.end());
  253. Chunks.reserve(128);
  254. for(;;) {
  255. LPCSTR q;
  256. for(;;) {
  257. if (p == end) {
  258. Chunks.push_back( Chunk(PlainText, p) );
  259. goto done;
  260. }
  261. if (*p == Delimiter)
  262. break;
  263. ++p;
  264. }
  265. q = ++p;
  266. comment = (p < end && *p == '*');
  267. for(;;) {
  268. if (p == end) {
  269. ReportError("Unmatched delimiters\n");
  270. exit(1);
  271. }
  272. if (*p == Delimiter) {
  273. if (comment) {
  274. if (p[-1] == '*') break;
  275. } else {
  276. break;
  277. }
  278. }
  279. ++p;
  280. }
  281. if (q-1 > PlainText) {
  282. Chunks.push_back( Chunk(PlainText, q-1) );
  283. }
  284. if (p == q) {
  285. // PERFPERF If the previous chunk was a text, we can extend it
  286. Chunks.push_back( Chunk(q-1, p) );
  287. } else {
  288. std::string x(q,p);
  289. if (x.compare(0, IF.size(), IF) == 0) {
  290. int previous = loop;
  291. // KLUDGE merge with FORALL
  292. if (loopLevel == MAX_LOOP_LEVEL) {
  293. ReportError("Too many nested blocks!\n");
  294. exit(1);
  295. }
  296. ++loopLevel;
  297. loop = static_cast<int>( Chunks.size() );
  298. DoIf(loopLevel, q,p);
  299. if (previous >= 32765) {
  300. ReportError("Too many chunks. Make loopEnd a UINT, %d\n", previous);
  301. exit(1);
  302. }
  303. Chunks.back().loopEnd = (SHORT)previous;
  304. while (p+1 < end && (p[1] == '\n' || p[1] == '\r') ) ++p;
  305. } else if (x.compare(0, FORALL.size(), FORALL) == 0) {
  306. int previous = loop;
  307. if (loopLevel == MAX_LOOP_LEVEL) {
  308. ReportError("Too many nested loops!\n");
  309. exit(1);
  310. }
  311. ++loopLevel;
  312. loop = static_cast<int>( Chunks.size() );
  313. DoLoop(loopLevel, q,p);
  314. if (previous >= 32765) {
  315. ReportError("Too many chunks. Make loopEnd a UINT, %d\n", previous);
  316. exit(1);
  317. }
  318. Chunks.back().loopEnd = (SHORT)previous;
  319. while (p+1 < end && (p[1] == '\n' || p[1] == '\r') ) ++p;
  320. } else if (x.compare(0, DELIMITER.size(), DELIMITER) == 0 && x.size() > 10) {
  321. Delimiter = x[10];
  322. } else if (x.compare(0, ENV.size(), ENV) == 0) {
  323. // we need to replace this field with
  324. // the value of the specified env variable
  325. LPCSTR val = getenv( std::string(q+4,p).c_str() );
  326. if (val != NULL) {
  327. Chunks.push_back( Chunk(std::string(val)) );
  328. }
  329. } else if (x.compare(0, COMMENT.size(), COMMENT) == 0) {
  330. // eat away the whitespace
  331. while (p+1 < end && (p[1] == '\n' || p[1] == '\r') ) ++p;
  332. } else if (x.compare(0, INCLUDE.size(), INCLUDE) == 0) { // Doesn't work
  333. Chunks.push_back(
  334. Chunk(actInclude, q + INCLUDE.size() + 1, p) );
  335. } else if ((x.compare(0, ENDIF.size(), ENDIF) == 0)
  336. || (x.compare(0, ENDFOR.size(), ENDFOR) == 0)) {
  337. // KLUDGE make them separate or rename both to simply END
  338. // End will be set in ENDFOR //
  339. if (loop == -1) {
  340. ReportError("ENDFOR without FORALL\n");
  341. exit(1);
  342. }
  343. ObjectMap.erase( Loop[loopLevel].Name );
  344. int previous = Chunks[loop].loopEnd;
  345. // BUGBUG have a check that confirms that we didn't run out of space
  346. Chunks[loop].loopEnd = (SHORT)Chunks.size();
  347. loop = previous;
  348. --loopLevel;
  349. while (p+1 < end && (p[1] == '\n' || p[1] == '\r') ) ++p;
  350. } else {
  351. DoVar(q, p);
  352. }
  353. }
  354. PlainText = ++p;
  355. }
  356. done:;
  357. if (loop != -1) {
  358. ReportError("No ENDFOR for loop, %d\n", loop);
  359. exit(1);
  360. }
  361. RunIt(0, static_cast<int>( Chunks.size() ), out);
  362. return 0;
  363. }
  364. };
  365. DWORD
  366. processTemplate(
  367. IN LPCSTR begin,
  368. IN LPCSTR end,
  369. IN EZPARSE_CALLBACK,
  370. IN PVOID Context,
  371. IN PEZPARSE_CONTEXT
  372. )
  373. {
  374. FILE *out = (FILE*)Context;
  375. TemplateProcessor tpl;
  376. return tpl.CompileAndRun(begin,end,out);
  377. }