ReactOS Fundraising Campaign 2012
 
€ 3,303 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

for.c

Go to the documentation of this file.
00001 /*
00002  *  FOR.C - for internal batch command.
00003  *
00004  *
00005  *  History:
00006  *
00007  *    16-Jul-1998 (Hans B Pufal)
00008  *        Started.
00009  *
00010  *    16-Jul-1998 (John P Price)
00011  *        Seperated commands into individual files.
00012  *
00013  *    19-Jul-1998 (Hans B Pufal)
00014  *        Implementation of FOR.
00015  *
00016  *    27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
00017  *        Added config.h include.
00018  *
00019  *    20-Jan-1999 (Eric Kohl)
00020  *        Unicode and redirection safe!
00021  *
00022  *    01-Sep-1999 (Eric Kohl)
00023  *        Added help text.
00024  *
00025  *    23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.se>)
00026  *        Implemented preservation of echo flag. Some other for related
00027  *        code in other files fixed, too.
00028  *
00029  *    28-Apr-2005 (Magnus Olsen) <magnus@greatlord.com>)
00030  *        Remove all hardcode string to En.rc
00031  */
00032 
00033 #include <precomp.h>
00034 
00035 
00036 /* FOR is a special command, so this function is only used for showing help now */
00037 INT cmd_for (LPTSTR param)
00038 {
00039     TRACE ("cmd_for (\'%s\')\n", debugstr_aw(param));
00040 
00041     if (!_tcsncmp (param, _T("/?"), 2))
00042     {
00043         ConOutResPaging(TRUE,STRING_FOR_HELP1);
00044         return 0;
00045     }
00046 
00047     error_syntax(param);
00048     return 1;
00049 }
00050 
00051 /* The stack of current FOR contexts.
00052  * NULL when no FOR command is active */
00053 LPFOR_CONTEXT fc = NULL;
00054 
00055 /* Get the next element of the FOR's list */
00056 static BOOL GetNextElement(TCHAR **pStart, TCHAR **pEnd)
00057 {
00058     TCHAR *p = *pEnd;
00059     BOOL InQuotes = FALSE;
00060     while (_istspace(*p))
00061         p++;
00062     if (!*p)
00063         return FALSE;
00064     *pStart = p;
00065     while (*p && (InQuotes || !_istspace(*p)))
00066         InQuotes ^= (*p++ == _T('"'));
00067     *pEnd = p;
00068     return TRUE;
00069 }
00070 
00071 /* Execute a single instance of a FOR command */
00072 static INT RunInstance(PARSED_COMMAND *Cmd)
00073 {
00074     if (bEcho && !bDisableBatchEcho && Cmd->Subcommands->Type != C_QUIET)
00075     {
00076         if (!bIgnoreEcho)
00077             ConOutChar(_T('\n'));
00078         PrintPrompt();
00079         EchoCommand(Cmd->Subcommands);
00080         ConOutChar(_T('\n'));
00081     }
00082     /* Just run the command (variable expansion is done in DoDelayedExpansion) */
00083     return ExecuteCommand(Cmd->Subcommands);
00084 }
00085 
00086 /* Check if this FOR should be terminated early */
00087 static BOOL Exiting(PARSED_COMMAND *Cmd)
00088 {
00089     /* Someone might have removed our context */
00090     return bCtrlBreak || fc != Cmd->For.Context;
00091 }
00092 
00093 /* Read the contents of a text file into memory,
00094  * dynamically allocating enough space to hold it all */
00095 static LPTSTR ReadFileContents(FILE *InputFile, TCHAR *Buffer)
00096 {
00097     SIZE_T Len = 0;
00098     SIZE_T AllocLen = 1000;
00099     LPTSTR Contents = cmd_alloc(AllocLen * sizeof(TCHAR));
00100     if (!Contents)
00101         return NULL;
00102 
00103     while (_fgetts(Buffer, CMDLINE_LENGTH, InputFile))
00104     {
00105         ULONG_PTR CharsRead = _tcslen(Buffer);
00106         while (Len + CharsRead >= AllocLen)
00107         {
00108             Contents = cmd_realloc(Contents, (AllocLen *= 2) * sizeof(TCHAR));
00109             if (!Contents)
00110                 return NULL;
00111         }
00112         _tcscpy(&Contents[Len], Buffer);
00113         Len += CharsRead;
00114     }
00115 
00116     Contents[Len] = _T('\0');
00117     return Contents;
00118 }
00119 
00120 static INT ForF(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer)
00121 {
00122     LPTSTR Delims = _T(" \t");
00123     TCHAR Eol = _T(';');
00124     INT SkipLines = 0;
00125     DWORD Tokens = (1 << 1);
00126     BOOL RemainderVar = FALSE;
00127     TCHAR StringQuote = _T('"');
00128     TCHAR CommandQuote = _T('\'');
00129     LPTSTR Variables[32];
00130     TCHAR *Start, *End;
00131     INT i;
00132     INT Ret = 0;
00133 
00134     if (Cmd->For.Params)
00135     {
00136         TCHAR Quote = 0;
00137         TCHAR *Param = Cmd->For.Params;
00138         if (*Param == _T('"') || *Param == _T('\''))
00139             Quote = *Param++;
00140 
00141         while (*Param && *Param != Quote)
00142         {
00143             if (*Param <= _T(' '))
00144             {
00145                 Param++;
00146             }
00147             else if (_tcsnicmp(Param, _T("delims="), 7) == 0)
00148             {
00149                 Param += 7;
00150                 /* delims=xxx: Specifies the list of characters that separate tokens */
00151                 Delims = Param;
00152                 while (*Param && *Param != Quote)
00153                 {
00154                     if (*Param == _T(' '))
00155                     {
00156                         TCHAR *FirstSpace = Param;
00157                         Param += _tcsspn(Param, _T(" "));
00158                         /* Exclude trailing spaces if this is not the last parameter */
00159                         if (*Param && *Param != Quote)
00160                             *FirstSpace = _T('\0');
00161                         break;
00162                     }
00163                     Param++;
00164                 }
00165                 if (*Param == Quote)
00166                     *Param++ = _T('\0');
00167             }
00168             else if (_tcsnicmp(Param, _T("eol="), 4) == 0)
00169             {
00170                 Param += 4;
00171                 /* eol=c: Lines starting with this character (may be
00172                  * preceded by delimiters) are skipped. */
00173                 Eol = *Param;
00174                 if (Eol != _T('\0'))
00175                     Param++;
00176             }
00177             else if (_tcsnicmp(Param, _T("skip="), 5) == 0)
00178             {
00179                 /* skip=n: Number of lines to skip at the beginning of each file */
00180                 SkipLines = _tcstol(Param + 5, &Param, 0);
00181                 if (SkipLines <= 0)
00182                     goto error;
00183             }
00184             else if (_tcsnicmp(Param, _T("tokens="), 7) == 0)
00185             {
00186                 Param += 7;
00187                 /* tokens=x,y,m-n: List of token numbers (must be between
00188                  * 1 and 31) that will be assigned into variables. */
00189                 Tokens = 0;
00190                 while (*Param && *Param != Quote && *Param != _T('*'))
00191                 {
00192                     INT First = _tcstol(Param, &Param, 0);
00193                     INT Last = First;
00194                     if (First < 1)
00195                         goto error;
00196                     if (*Param == _T('-'))
00197                     {
00198                         /* It's a range of tokens */
00199                         Last = _tcstol(Param + 1, &Param, 0);
00200                         if (Last < First || Last > 31)
00201                             goto error;
00202                     }
00203                     Tokens |= (2 << Last) - (1 << First);
00204 
00205                     if (*Param != _T(','))
00206                         break;
00207                     Param++;
00208                 }
00209                 /* With an asterisk at the end, an additional variable
00210                  * will be created to hold the remainder of the line
00211                  * (after the last token specified). */
00212                 if (*Param == _T('*'))
00213                 {
00214                     RemainderVar = TRUE;
00215                     Param++;
00216                 }
00217             }
00218             else if (_tcsnicmp(Param, _T("useback"), 7) == 0)
00219             {
00220                 Param += 7;
00221                 /* usebackq: Use alternate quote characters */
00222                 StringQuote = _T('\'');
00223                 CommandQuote = _T('`');
00224                 /* Can be written as either "useback" or "usebackq" */
00225                 if (_totlower(*Param) == _T('q'))
00226                     Param++;
00227             }
00228             else
00229             {
00230             error:
00231                 error_syntax(Param);
00232                 return 1;
00233             }
00234         }
00235     }
00236 
00237     /* Count how many variables will be set: one for each token,
00238      * plus maybe one for the remainder */
00239     fc->varcount = RemainderVar;
00240     for (i = 1; i < 32; i++)
00241         fc->varcount += (Tokens >> i & 1);
00242     fc->values = Variables;
00243 
00244     if (*List == StringQuote || *List == CommandQuote)
00245     {
00246         /* Treat the entire "list" as one single element */
00247         Start = List;
00248         End = &List[_tcslen(List)];
00249         goto single_element;
00250     }
00251 
00252     End = List;
00253     while (GetNextElement(&Start, &End))
00254     {
00255         FILE *InputFile;
00256         LPTSTR FullInput, In, NextLine;
00257         INT Skip;
00258     single_element:
00259 
00260         if (*Start == StringQuote && End[-1] == StringQuote)
00261         {
00262             /* Input given directly as a string */
00263             End[-1] = _T('\0');
00264             FullInput = cmd_dup(Start + 1);
00265         }
00266         else if (*Start == CommandQuote && End[-1] == CommandQuote)
00267         {
00268             /* Read input from a command */
00269             End[-1] = _T('\0');
00270             InputFile = _tpopen(Start + 1, _T("r"));
00271             if (!InputFile)
00272             {
00273                 error_bad_command(Start + 1);
00274                 return 1;
00275             }
00276             FullInput = ReadFileContents(InputFile, Buffer);
00277             _pclose(InputFile);
00278         }
00279         else
00280         {
00281             /* Read input from a file */
00282             TCHAR Temp = *End;
00283             *End = _T('\0');
00284             StripQuotes(Start);
00285             InputFile = _tfopen(Start, _T("r"));
00286             *End = Temp;
00287             if (!InputFile)
00288             {
00289                 error_sfile_not_found(Start);
00290                 return 1;
00291             }
00292             FullInput = ReadFileContents(InputFile, Buffer);
00293             fclose(InputFile);
00294         }
00295 
00296         if (!FullInput)
00297         {
00298             error_out_of_memory();
00299             return 1;
00300         }
00301 
00302         /* Loop over the input line by line */
00303         In = FullInput;
00304         Skip = SkipLines;
00305         do
00306         {
00307             DWORD RemainingTokens = Tokens;
00308             LPTSTR *CurVar = Variables;
00309 
00310             NextLine = _tcschr(In, _T('\n'));
00311             if (NextLine)
00312                 *NextLine++ = _T('\0');
00313 
00314             if (--Skip >= 0)
00315                 continue;
00316 
00317             /* Ignore lines where the first token starts with the eol character */
00318             In += _tcsspn(In, Delims);
00319             if (*In == Eol)
00320                 continue;
00321 
00322             while ((RemainingTokens >>= 1) != 0)
00323             {
00324                 /* Save pointer to this token in a variable if requested */
00325                 if (RemainingTokens & 1)
00326                     *CurVar++ = In;
00327                 /* Find end of token */
00328                 In += _tcscspn(In, Delims);
00329                 /* Nul-terminate it and advance to next token */
00330                 if (*In)
00331                 {
00332                     *In++ = _T('\0');
00333                     In += _tcsspn(In, Delims);
00334                 }
00335             }
00336             /* Save pointer to remainder of line */
00337             *CurVar = In;
00338 
00339             /* Don't run unless the line had enough tokens to fill at least one variable */
00340             if (*Variables[0])
00341                 Ret = RunInstance(Cmd);
00342         } while (!Exiting(Cmd) && (In = NextLine) != NULL);
00343         cmd_free(FullInput);
00344     }
00345 
00346     return Ret;
00347 }
00348 
00349 /* FOR /L: Do a numeric loop */
00350 static INT ForLoop(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer)
00351 {
00352     enum { START, STEP, END };
00353     INT params[3] = { 0, 0, 0 };
00354     INT i;
00355     INT Ret = 0;
00356 
00357     TCHAR *Start, *End = List;
00358     for (i = 0; i < 3 && GetNextElement(&Start, &End); i++)
00359         params[i] = _tcstol(Start, NULL, 0);
00360 
00361     i = params[START];
00362     while (!Exiting(Cmd) &&
00363            (params[STEP] >= 0 ? (i <= params[END]) : (i >= params[END])))
00364     {
00365         _itot(i, Buffer, 10);
00366         Ret = RunInstance(Cmd);
00367         i += params[STEP];
00368     }
00369     return Ret;
00370 }
00371 
00372 /* Process a FOR in one directory. Stored in Buffer (up to BufPos) is a
00373  * string which is prefixed to each element of the list. In a normal FOR
00374  * it will be empty, but in FOR /R it will be the directory name. */
00375 static INT ForDir(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer, TCHAR *BufPos)
00376 {
00377     TCHAR *Start, *End = List;
00378     INT Ret = 0;
00379     while (!Exiting(Cmd) && GetNextElement(&Start, &End))
00380     {
00381         if (BufPos + (End - Start) > &Buffer[CMDLINE_LENGTH])
00382             continue;
00383         memcpy(BufPos, Start, (End - Start) * sizeof(TCHAR));
00384         BufPos[End - Start] = _T('\0');
00385 
00386         if (_tcschr(BufPos, _T('?')) || _tcschr(BufPos, _T('*')))
00387         {
00388             WIN32_FIND_DATA w32fd;
00389             HANDLE hFind;
00390             TCHAR *FilePart;
00391 
00392             StripQuotes(BufPos);
00393             hFind = FindFirstFile(Buffer, &w32fd);
00394             if (hFind == INVALID_HANDLE_VALUE)
00395                 continue;
00396             FilePart = _tcsrchr(BufPos, _T('\\'));
00397             FilePart = FilePart ? FilePart + 1 : BufPos;
00398             do
00399             {
00400                 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
00401                     continue;
00402                 if (!(w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
00403                     != !(Cmd->For.Switches & FOR_DIRS))
00404                     continue;
00405                 if (_tcscmp(w32fd.cFileName, _T(".")) == 0 ||
00406                     _tcscmp(w32fd.cFileName, _T("..")) == 0)
00407                     continue;
00408                 _tcscpy(FilePart, w32fd.cFileName);
00409                 Ret = RunInstance(Cmd);
00410             } while (!Exiting(Cmd) && FindNextFile(hFind, &w32fd));
00411             FindClose(hFind);
00412         }
00413         else
00414         {
00415             Ret = RunInstance(Cmd);
00416         }
00417     }
00418     return Ret;
00419 }
00420 
00421 /* FOR /R: Process a FOR in each directory of a tree, recursively. */
00422 static INT ForRecursive(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer, TCHAR *BufPos)
00423 {
00424     HANDLE hFind;
00425     WIN32_FIND_DATA w32fd;
00426     INT Ret = 0;
00427 
00428     if (BufPos[-1] != _T('\\'))
00429     {
00430         *BufPos++ = _T('\\');
00431         *BufPos = _T('\0');
00432     }
00433 
00434     Ret = ForDir(Cmd, List, Buffer, BufPos);
00435 
00436     _tcscpy(BufPos, _T("*"));
00437     hFind = FindFirstFile(Buffer, &w32fd);
00438     if (hFind == INVALID_HANDLE_VALUE)
00439         return Ret;
00440     do
00441     {
00442         if (!(w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
00443             continue;
00444         if (_tcscmp(w32fd.cFileName, _T(".")) == 0 ||
00445             _tcscmp(w32fd.cFileName, _T("..")) == 0)
00446             continue;
00447         Ret = ForRecursive(Cmd, List, Buffer, _stpcpy(BufPos, w32fd.cFileName));
00448     } while (!Exiting(Cmd) && FindNextFile(hFind, &w32fd));
00449     FindClose(hFind);
00450     return Ret;
00451 }
00452 
00453 BOOL
00454 ExecuteFor(PARSED_COMMAND *Cmd)
00455 {
00456     TCHAR Buffer[CMDLINE_LENGTH]; /* Buffer to hold the variable value */
00457     LPTSTR BufferPtr = Buffer;
00458     LPFOR_CONTEXT lpNew;
00459     INT Ret;
00460     LPTSTR List = DoDelayedExpansion(Cmd->For.List);
00461 
00462     if (!List)
00463         return 1;
00464 
00465     /* Create our FOR context */
00466     lpNew = cmd_alloc(sizeof(FOR_CONTEXT));
00467     if (!lpNew)
00468     {
00469         cmd_free(List);
00470         return 1;
00471     }
00472     lpNew->prev = fc;
00473     lpNew->firstvar = Cmd->For.Variable;
00474     lpNew->varcount = 1;
00475     lpNew->values = &BufferPtr;
00476 
00477     Cmd->For.Context = lpNew;
00478     fc = lpNew;
00479 
00480     if (Cmd->For.Switches & FOR_F)
00481     {
00482         Ret = ForF(Cmd, List, Buffer);
00483     }
00484     else if (Cmd->For.Switches & FOR_LOOP)
00485     {
00486         Ret = ForLoop(Cmd, List, Buffer);
00487     }
00488     else if (Cmd->For.Switches & FOR_RECURSIVE)
00489     {
00490         DWORD Len = GetFullPathName(Cmd->For.Params ? Cmd->For.Params : _T("."),
00491                                     MAX_PATH, Buffer, NULL);
00492         Ret = ForRecursive(Cmd, List, Buffer, &Buffer[Len]);
00493     }
00494     else
00495     {
00496         Ret = ForDir(Cmd, List, Buffer, Buffer);
00497     }
00498 
00499     /* Remove our context, unless someone already did that */
00500     if (fc == lpNew)
00501         fc = lpNew->prev;
00502 
00503     cmd_free(lpNew);
00504     cmd_free(List);
00505     return Ret;
00506 }
00507 
00508 /* EOF */

Generated on Tue May 15 04:40:09 2012 for ReactOS by doxygen 1.6.3

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.