Counter Strike : Global Offensive Source Code
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.

472 lines
10 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include <ctype.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include "tokenreader.h"
  11. #include "tier0/platform.h"
  12. #include "tier1/strtools.h"
  13. #include "tier0/dbg.h"
  14. // NOTE: This has to be the last file included!
  15. #include "tier0/memdbgon.h"
  16. //-----------------------------------------------------------------------------
  17. // Purpose:
  18. //-----------------------------------------------------------------------------
  19. TokenReader::TokenReader(void)
  20. {
  21. m_szFilename[0] = '\0';
  22. m_nLine = 1;
  23. m_nErrorCount = 0;
  24. m_bStuffed = false;
  25. }
  26. //-----------------------------------------------------------------------------
  27. // Purpose:
  28. // Input : *pszFilename -
  29. // Output : Returns true on success, false on failure.
  30. //-----------------------------------------------------------------------------
  31. bool TokenReader::Open(const char *pszFilename)
  32. {
  33. m_file.Open( pszFilename, NULL, CUtlBuffer::READ_ONLY );
  34. Q_strncpy(m_szFilename, pszFilename, sizeof( m_szFilename ) );
  35. m_nLine = 1;
  36. m_nErrorCount = 0;
  37. m_bStuffed = false;
  38. return m_file.IsOpen();
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Purpose:
  42. //-----------------------------------------------------------------------------
  43. void TokenReader::Close()
  44. {
  45. m_file.Close();
  46. }
  47. //-----------------------------------------------------------------------------
  48. // Purpose:
  49. // Input : *error -
  50. // Output : const char
  51. //-----------------------------------------------------------------------------
  52. const char *TokenReader::Error(char *error, ...)
  53. {
  54. static char szErrorBuf[256];
  55. Q_snprintf(szErrorBuf, sizeof( szErrorBuf ), "File %s, line %d: ", m_szFilename, m_nLine);
  56. Q_strncat(szErrorBuf, error, sizeof( szErrorBuf ), COPY_ALL_CHARACTERS );
  57. m_nErrorCount++;
  58. return(szErrorBuf);
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Purpose:
  62. // Input : pszStore -
  63. // nSize -
  64. // Output : Returns true on success, false on failure.
  65. //-----------------------------------------------------------------------------
  66. trtoken_t TokenReader::GetString(char *pszStore, int nSize)
  67. {
  68. if (nSize <= 0)
  69. {
  70. return TOKENERROR;
  71. }
  72. char szBuf[1024];
  73. //
  74. // Until we reach the end of this string or run out of room in
  75. // the destination buffer...
  76. //
  77. while (true)
  78. {
  79. //
  80. // Fetch the next batch of text from the file.
  81. //
  82. int writePos = 0;
  83. const char *pToken = NULL;
  84. while ( NULL != (pToken = (const char *)m_file.PeekGet( sizeof(char), 0 )) )
  85. {
  86. if ( pToken[0] == '\"' )
  87. break;
  88. if ( writePos < (sizeof(szBuf)-1) )
  89. {
  90. szBuf[writePos++] = m_file.GetChar();
  91. }
  92. }
  93. szBuf[writePos] = 0;
  94. pToken = (const char *)m_file.PeekGet( sizeof(char), 0 );
  95. if (!pToken)
  96. return TOKENEOF;
  97. //
  98. // Transfer the text to the destination buffer.
  99. //
  100. char *pszSrc = szBuf;
  101. while ((*pszSrc != '\0') && (nSize > 1))
  102. {
  103. if (*pszSrc == '\n')
  104. {
  105. //
  106. // Newline encountered before closing quote -- unterminated string.
  107. //
  108. *pszStore = '\0';
  109. return TOKENSTRINGTOOLONG;
  110. }
  111. else if (*pszSrc != '\\')
  112. {
  113. *pszStore = *pszSrc;
  114. pszSrc++;
  115. }
  116. else
  117. {
  118. //
  119. // Backslash sequence - replace with the appropriate character.
  120. //
  121. pszSrc++;
  122. if (*pszSrc == 'n')
  123. {
  124. *pszStore = '\n';
  125. }
  126. pszSrc++;
  127. }
  128. pszStore++;
  129. nSize--;
  130. }
  131. if (*pszSrc != '\0')
  132. {
  133. //
  134. // Ran out of room in the destination buffer.
  135. // terminate the string, and exit.
  136. //
  137. *pszStore = '\0';
  138. return TOKENSTRINGTOOLONG;
  139. }
  140. //
  141. // Check for closing quote.
  142. //
  143. if (pToken[0] == '\"')
  144. {
  145. //
  146. // Eat the close quote and any whitespace.
  147. //
  148. m_file.GetChar();
  149. bool bCombineStrings = SkipWhiteSpace();
  150. //
  151. // Combine consecutive quoted strings if the combine strings character was
  152. // encountered between the two strings.
  153. //
  154. pToken = (const char *)m_file.PeekGet( sizeof(char), 0 );
  155. if (bCombineStrings && pToken && (pToken[0] == '\"'))
  156. {
  157. //
  158. // Eat the open quote and keep parsing this string.
  159. //
  160. m_file.GetChar();
  161. }
  162. else
  163. {
  164. //
  165. // Done with this string, terminate the string and exit.
  166. //
  167. *pszStore = '\0';
  168. return STRING;
  169. }
  170. }
  171. }
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Purpose: Returns the next token, allocating enough memory to store the token
  175. // plus a terminating NULL.
  176. // Input : pszStore - Pointer to a string that will be allocated.
  177. // Output : Returns the type of token that was read, or TOKENERROR.
  178. //-----------------------------------------------------------------------------
  179. trtoken_t TokenReader::NextTokenDynamic(char **ppszStore)
  180. {
  181. char szTempBuffer[8192];
  182. trtoken_t eType = NextToken(szTempBuffer, sizeof(szTempBuffer));
  183. int len = Q_strlen(szTempBuffer) + 1;
  184. *ppszStore = new char [len];
  185. Assert( *ppszStore );
  186. Q_strncpy(*ppszStore, szTempBuffer, len );
  187. return(eType);
  188. }
  189. //-----------------------------------------------------------------------------
  190. // Purpose: Returns the next token.
  191. // Input : pszStore - Pointer to a string that will receive the token.
  192. // Output : Returns the type of token that was read, or TOKENERROR.
  193. //-----------------------------------------------------------------------------
  194. trtoken_t TokenReader::NextToken(char *pszStore, int nSize)
  195. {
  196. char *pStart = pszStore;
  197. //
  198. // If they stuffed a token, return that token.
  199. //
  200. if (m_bStuffed)
  201. {
  202. m_bStuffed = false;
  203. Q_strncpy( pszStore, m_szStuffed, nSize );
  204. return m_eStuffed;
  205. }
  206. SkipWhiteSpace();
  207. if ( !m_file.PeekGet(1,0) )
  208. return TOKENEOF;
  209. char ch = *(const char *)m_file.PeekGet( sizeof(char), 0 );
  210. //
  211. // Look for all the valid operators.
  212. //
  213. switch (ch)
  214. {
  215. case '@':
  216. case ',':
  217. case '!':
  218. case '+':
  219. case '&':
  220. case '*':
  221. case '$':
  222. case '.':
  223. case '=':
  224. case ':':
  225. case '[':
  226. case ']':
  227. case '(':
  228. case ')':
  229. case '{':
  230. case '}':
  231. case '\\':
  232. {
  233. pszStore[0] = ch;
  234. pszStore[1] = 0;
  235. m_file.GetChar(); // used char
  236. return OPERATOR;
  237. }
  238. }
  239. //
  240. // Look for the start of a quoted string.
  241. //
  242. if (ch == '\"')
  243. {
  244. m_file.GetChar(); // used char
  245. return GetString(pszStore, nSize);
  246. }
  247. //
  248. // Integers consist of numbers with an optional leading minus sign.
  249. //
  250. if (V_isdigit(ch) || (ch == '-'))
  251. {
  252. do
  253. {
  254. if ( (pszStore - pStart + 1) < nSize )
  255. {
  256. m_file.GetChar(); // used char
  257. *pszStore = ch;
  258. pszStore++;
  259. }
  260. ch = *(const char *)m_file.PeekGet( sizeof(char), 0 );
  261. if (ch == '-')
  262. {
  263. m_file.GetChar(); // used char
  264. return TOKENERROR;
  265. }
  266. } while (V_isdigit(ch));
  267. //
  268. // No identifier characters are allowed contiguous with numbers.
  269. //
  270. if (V_isalpha(ch) || (ch == '_'))
  271. {
  272. m_file.GetChar(); // used char
  273. return TOKENERROR;
  274. }
  275. *pszStore = '\0';
  276. return INTEGER;
  277. }
  278. //
  279. // Identifiers consist of a consecutive string of alphanumeric
  280. // characters and underscores.
  281. //
  282. while ( V_isalpha(ch) || V_isdigit(ch) || (ch == '_') )
  283. {
  284. if ( (pszStore - pStart + 1) < nSize )
  285. {
  286. m_file.GetChar(); // used char
  287. *pszStore = ch;
  288. pszStore++;
  289. }
  290. ch = *(const char *)m_file.PeekGet( sizeof(char), 0 );
  291. }
  292. *pszStore = '\0';
  293. return IDENT;
  294. }
  295. //-----------------------------------------------------------------------------
  296. // Purpose:
  297. // Input : ttype -
  298. // *pszToken -
  299. //-----------------------------------------------------------------------------
  300. void TokenReader::IgnoreTill(trtoken_t ttype, const char *pszToken)
  301. {
  302. trtoken_t _ttype;
  303. char szBuf[1024];
  304. while(1)
  305. {
  306. _ttype = NextToken(szBuf, sizeof(szBuf));
  307. if(_ttype == TOKENEOF)
  308. return;
  309. if(_ttype == ttype)
  310. {
  311. if(IsToken(pszToken, szBuf))
  312. {
  313. Stuff(ttype, pszToken);
  314. return;
  315. }
  316. }
  317. }
  318. }
  319. //-----------------------------------------------------------------------------
  320. // Purpose:
  321. // Input : ttype -
  322. // pszToken -
  323. //-----------------------------------------------------------------------------
  324. void TokenReader::Stuff(trtoken_t eType, const char *pszToken)
  325. {
  326. m_eStuffed = eType;
  327. Q_strncpy(m_szStuffed, pszToken, sizeof( m_szStuffed ) );
  328. m_bStuffed = true;
  329. }
  330. //-----------------------------------------------------------------------------
  331. // Purpose:
  332. // Input : ttype -
  333. // pszToken -
  334. // Output : Returns true on success, false on failure.
  335. //-----------------------------------------------------------------------------
  336. bool TokenReader::Expecting(trtoken_t ttype, const char *pszToken)
  337. {
  338. char szBuf[1024];
  339. if (NextToken(szBuf, sizeof(szBuf)) != ttype || !IsToken(pszToken, szBuf))
  340. {
  341. return false;
  342. }
  343. return true;
  344. }
  345. //-----------------------------------------------------------------------------
  346. // Purpose:
  347. // Input : pszStore -
  348. // Output :
  349. //-----------------------------------------------------------------------------
  350. trtoken_t TokenReader::PeekTokenType(char *pszStore, int maxlen )
  351. {
  352. if (!m_bStuffed)
  353. {
  354. m_eStuffed = NextToken(m_szStuffed, sizeof(m_szStuffed));
  355. m_bStuffed = true;
  356. }
  357. if (pszStore)
  358. {
  359. Q_strncpy(pszStore, m_szStuffed, maxlen );
  360. }
  361. return(m_eStuffed);
  362. }
  363. //-----------------------------------------------------------------------------
  364. // Purpose: Gets the next non-whitespace character from the file.
  365. // Input : ch - Receives the character.
  366. // Output : Returns true if the whitespace contained the combine strings
  367. // character '+', which is used to merge consecutive quoted strings.
  368. //-----------------------------------------------------------------------------
  369. bool TokenReader::SkipWhiteSpace(void)
  370. {
  371. bool bCombineStrings = false;
  372. while ( m_file.PeekGet(1,0) )
  373. {
  374. char ch = *(const char *)m_file.PeekGet( sizeof(char), 0 );
  375. // whitespace, skip
  376. if ((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == 0))
  377. {
  378. m_file.GetChar();
  379. continue;
  380. }
  381. // string continuation
  382. if (ch == '+')
  383. {
  384. m_file.GetChar();
  385. bCombineStrings = true;
  386. continue;
  387. }
  388. // newline, count and advance
  389. if (ch == '\n')
  390. {
  391. m_file.GetChar();
  392. m_nLine++;
  393. continue;
  394. }
  395. // Deal with c++ style comments
  396. const char *pPeek = (const char *)m_file.PeekGet( 2 * sizeof(char), 0 );
  397. if ( pPeek && ( pPeek[0] == '/' ) && ( pPeek[1] == '/' ) )
  398. {
  399. // read complete line
  400. for ( char c = m_file.GetChar(); m_file.IsValid(); c = m_file.GetChar() )
  401. {
  402. if ( c == '\n' )
  403. break;
  404. }
  405. m_nLine++;
  406. continue;
  407. }
  408. break;
  409. }
  410. return bCombineStrings;
  411. }