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.

347 lines
12 KiB

  1. // COMMAND.C - NMAKE 'command line' handling routines
  2. //
  3. // Copyright (c) 1988-1990, Microsoft Corporation. All rights reserved.
  4. //
  5. // Purpose:
  6. // Module contains routines to handle NMAKE 'command line' syntax. NMAKE can be
  7. // optionally called by using the syntax 'NMAKE @commandfile'. This allows more
  8. // flexibility and preents a way of getting around DOS's 128-byte limit on the
  9. // length of a command line. Additionally, it saves keystrokes for frequently
  10. // run commands for NMAKE.
  11. //
  12. // Revision History:
  13. // 04-Feb-2000 BTF Ported to Win64
  14. // 15-Nov-1993 JR Major speed improvements
  15. // 15-Oct-1993 HV Use tchar.h instead of mbstring.h directly, change STR*() to _ftcs*()
  16. // 10-May-1993 HV Add include file mbstring.h
  17. // Change the str* functions to STR*
  18. // 14-Aug-1992 SS CAVIAR 2735: handle quoted macro values in command files
  19. // 02-Feb-1990 SB Replace fopen() by FILEOPEN
  20. // 01-Dec-1989 SB Changed realloc() to REALLOC()
  21. // 22-Nov-1989 SB Changed free() to FREE()
  22. // 17-Aug-1989 SB Add error check to closing file
  23. // 05-Apr-1989 SB made func calls NEAR to put all funcs into 1 module
  24. // 20-Oct-1988 SB Notes added to readCommandFile()
  25. // 17-Aug-1988 RB Clean up.
  26. #include "precomp.h"
  27. #pragma hdrstop
  28. void addArgument(char*,unsigned,char***);
  29. void processLine(char*,unsigned*,char***);
  30. void tokenizeLine(char*,unsigned*,char***);
  31. // readCommandFile()
  32. //
  33. // arguments: name pointer to name of command file to read
  34. //
  35. // actions: opens command file
  36. // reads in lines and calls processLine() to
  37. // break them into tokens and to build
  38. // an argument vector (a la argv[])
  39. // calls parseCommandLine() recursively to process
  40. // the accumulated "command line" arguments
  41. // frees space used by the arg vector
  42. //
  43. // modifies: makeFiles in main() by modifying contents of parameter list
  44. // makeTargets in main() by modifying contents of targets parameter
  45. // buf global buffer
  46. //
  47. // notes: function is not ANSI portable because it uses fopen()
  48. // with "rt" type and text mode is a Microsoft extension
  49. //
  50. void
  51. readCommandFile(
  52. char *name
  53. )
  54. {
  55. char *s, // buffer
  56. **vector; // local versions of arg vector
  57. unsigned count = 0; // count
  58. size_t n;
  59. if (!(file = FILEOPEN(name,"rt")))
  60. makeError(0,CANT_OPEN_FILE,name);
  61. vector = NULL; // no args yet
  62. while (fgets(buf,MAXBUF,file)) {
  63. n = _tcslen(buf);
  64. // if we didn't get the whole line, OR the line ended with a backSlash
  65. if ((n == MAXBUF-1 && buf[n-1] != '\n') ||
  66. (buf[n-1] == '\n' && buf[n-2] == '\\')
  67. ) {
  68. if (buf[n-2] == '\\' && buf[n-1] == '\n') {
  69. // Replace \n by \0 and \\ by a space; Also reset length
  70. buf[n-1] = '\0';
  71. buf[n-2] = ' ';
  72. n--;
  73. }
  74. s = makeString(buf);
  75. getRestOfLine(&s,&n);
  76. } else
  77. s = buf;
  78. processLine(s,&count,&vector); // separate into args
  79. if (s != buf)
  80. FREE(s);
  81. }
  82. if (fclose(file) == EOF)
  83. makeError(0, ERROR_CLOSING_FILE, name);
  84. parseCommandLine(count,vector); // evaluate the args
  85. while (count--) // free the arg vector
  86. if(vector[count])
  87. FREE(vector[count]); // NULL entries mean that the space the
  88. } // entry used to pt to is still in use
  89. // getRestOfLine()
  90. //
  91. // arguments: s pointer to readCommandFile()'s buffer
  92. // holding line so far
  93. // n pointer to readCommandFile()'s count of
  94. // the chars in *s
  95. //
  96. // actions: keeps reading in text until it sees a newline
  97. // or the end of file
  98. // reallocs space for the old buffer plus the
  99. // contents of the new buffer each time
  100. // appends new buffer's text to existing text
  101. //
  102. // modifies: s readCommandFile()'s text buffer by realloc'ing
  103. // more space for incoming text
  104. // n readCommandFile()'s count of bytes in s
  105. // buf global buffer
  106. void
  107. getRestOfLine(
  108. char *s[],
  109. size_t *n
  110. )
  111. {
  112. size_t temp;
  113. char *t;
  114. t = buf;
  115. while ((*s)[*n-1] != '\n') { // get rest of line
  116. if (!fgets(t,MAXBUF,file))
  117. break; // we hit EOF
  118. temp = _tcslen(t);
  119. if (t[temp-2] == '\\' && t[temp-1] == '\n') {
  120. //Replace \n by \0 and \\ by a space; Also reset length
  121. t[temp-1] = '\0';
  122. t[temp-2] = ' ';
  123. }
  124. temp = *n;
  125. *n += _tcslen(t);
  126. {
  127. void *pv = REALLOC(*s,*n+1); // + 1 for NULL byte
  128. if (!pv)
  129. makeError(line, MACRO_TOO_LONG);
  130. else
  131. *s = (char *)pv;
  132. }
  133. _tcscpy(*s+temp,t);
  134. }
  135. }
  136. // processLine()
  137. //
  138. // arguments: s pointer to readCommandFile()'s buffer
  139. // holding "command line" to be processed
  140. // count pointer to readCommandFile()'s count of
  141. // "command line" arguments seen so far
  142. // vector pointer to readCommandFile()'s vector of
  143. // pointers to character strings
  144. //
  145. // actions: if the line to be broken into "command line arguments" contains '"'
  146. // breaks all the text before '"' into tokens
  147. // delimited by whitespace (which get put in vector[] by
  148. // tokenizeLine())
  149. // finds the closing '"' and treats the quoted string
  150. // as a single token, adding it to the vector
  151. // recurses on the tail of the line (to check for
  152. // other quoted strings)
  153. // else breaks all text in line into tokens delimited
  154. // by whitespace
  155. //
  156. // modifies: vector readCommandFile()'s vector of pointers to
  157. // "command line argument" strings (by modifying
  158. // the contents of the parameter pointer, vector)
  159. // count readCommandFile()'s count of the arguments in
  160. // the vector (by modifying the contents of the
  161. // parameter pointer, count)
  162. void
  163. processLine(
  164. char *s,
  165. unsigned *count,
  166. char **vector[]
  167. )
  168. {
  169. char *t;
  170. char *u;
  171. size_t m;
  172. size_t n;
  173. BOOL allocFlag = FALSE;
  174. if (!(t = _tcschr(s,'"'))) { // no quoted strings,
  175. tokenizeLine(s,count,vector); // just standard fare
  176. } else {
  177. // There are two kinds of situations in which quotes can occur:
  178. // 1. "FOO = bar baz"
  179. // 2. FOO="bar baz"
  180. if ((t == s) || (*(t-1) != '=')) {
  181. // Case 1 above
  182. *t++ = '\0'; // quoted macrodef
  183. tokenizeLine(s,count,vector); // get tokens before "
  184. } else {
  185. // Case 2 above
  186. *t-- = ' ';
  187. for (u = t; u > s; --u) // find the beginning of the macro name
  188. if (*u == ' ' || *u == '\t' || *u == '\n')
  189. break;
  190. if (u != s) {
  191. *u++ = '\0';
  192. tokenizeLine(s, count, vector);
  193. }
  194. t = u;
  195. }
  196. n = _tcslen(t);
  197. for (u = t; *u; ++u) { // look for closing "
  198. if (*u == '"') { // need " and not ""
  199. if (*(u+1) == '"') {
  200. _tcscpy(u,u+1);
  201. continue;
  202. }
  203. *u++ = '\0'; // terminate macrodef
  204. addArgument(t,*count,vector); // treat as one arg
  205. ++*count;
  206. processLine(u+1,count,vector); // recurse on rest of line
  207. break;
  208. } // TAIL RECURSION -- eliminate later?
  209. if ((*u == '\\')
  210. && WHITESPACE(*(u-1))
  211. && (*(u+1) == '\n')) { // \n always last char
  212. *u = '\0'; // 2 chars go to 1
  213. m = (n = n-2); // adjust length count
  214. if (!allocFlag) {
  215. allocFlag = TRUE;
  216. t = makeString(t);
  217. }
  218. getRestOfLine(&t,&n); // get some more text
  219. u = t + m ; // reset u & continue looping
  220. }
  221. }
  222. if (u == t + n) { // if at end of line
  223. makeError(0,SYNTAX_NO_QUOTE); // and no ", error
  224. }
  225. if (allocFlag) {
  226. FREE(t);
  227. }
  228. }
  229. }
  230. // tokenizeLine()
  231. //
  232. // arguments: s pointer to readCommandFile()'s buffer
  233. // holding "command line" to be tokenized
  234. // count pointer to readCommandFile()'s count of
  235. // "command line" arguments seen so far
  236. // vector pointer to readCommandFile()'s vector of
  237. // pointers to character strings
  238. //
  239. // actions: breaks the line in s into tokens (command line
  240. // arguments) delimited by whitespace
  241. // adds each token to the argument vector
  242. // adjusts the argument counter
  243. //
  244. // modifies: vector readCommandFile()'s vector of pointers to
  245. // "command line argument" strings (by modifying
  246. // the contents of the parameter pointer, vector)
  247. // count readCommandFile()'s count of the arguments in
  248. // the vector (by modifying the contents of the
  249. // parameter pointer, count)
  250. //
  251. // If the user ever wants '@' to be part of an argument in a command file,
  252. // he has to enclose that argument in quotation marks.
  253. void
  254. tokenizeLine( // gets args delimited
  255. char *s, // by whitespace and
  256. unsigned *count, // constructs an arg
  257. char **vector[] // vector
  258. )
  259. {
  260. char *t;
  261. if (t = _tcschr(s,'\\')) {
  262. if (WHITESPACE(*(t-1)) && (*(t+1) == '\n')) {
  263. *t = '\0';
  264. }
  265. }
  266. for (t = _tcstok(s," \t\n"); t; t = _tcstok(NULL," \t\n")) {
  267. if (*t == '@') {
  268. makeError(0,SYNTAX_CMDFILE,t+1);
  269. break; // should we keep on parsing here?
  270. }
  271. addArgument(t,*count,vector);
  272. ++*count;
  273. }
  274. }
  275. // addArgument()
  276. //
  277. // arguments: s pointer to text of argument to be added
  278. // to the "command line argument" vector
  279. // count pointer to readCommandFile()'s count of
  280. // "command line" arguments seen so far
  281. // vector pointer to readCommandFile()'s vector of
  282. // pointers to character strings
  283. //
  284. // actions: allocates space in the vector for the new argument
  285. // allocates space for argument string
  286. // makes vector entry point to argument string
  287. //
  288. // modifies: vector readCommandFile()'s vector of pointers to
  289. // "command line argument" strings (by modifying
  290. // the contents of the parameter pointer, vector)
  291. // (count gets incremented by caller)
  292. //
  293. // To keep from fragmenting memory by doing many realloc() calls for very
  294. // small amounts of space, we get memory in small chunks and use that until
  295. // it is depleted, then we get another chunk . . . .
  296. void
  297. addArgument( // puts s in vector
  298. char *s,
  299. unsigned count,
  300. char **vector[]
  301. )
  302. {
  303. if (!(*vector)) {
  304. *vector = (char**) allocate(CHUNKSIZE*sizeof(char*));
  305. } else if (!(count % CHUNKSIZE)) {
  306. void *pv = REALLOC(*vector,(count+CHUNKSIZE)*sizeof(char*));
  307. if (!pv) {
  308. makeError(0,OUT_OF_MEMORY);
  309. } else {
  310. *vector = (char**) pv;
  311. }
  312. }
  313. (*vector)[count] = makeString(s);
  314. }