示例#1
0
void WCMD_directory (WCHAR *cmd)
{
  WCHAR path[MAX_PATH], cwd[MAX_PATH];
  DWORD status;
  CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
  WCHAR *p;
  WCHAR string[MAXSTRING];
  int   argno         = 0;
  WCHAR *argN          = cmd;
  WCHAR  lastDrive;
  BOOL  trailerReqd = FALSE;
  DIRECTORY_STACK *fullParms = NULL;
  DIRECTORY_STACK *prevEntry = NULL;
  DIRECTORY_STACK *thisEntry = NULL;
  WCHAR drive[10];
  WCHAR dir[MAX_PATH];
  WCHAR fname[MAX_PATH];
  WCHAR ext[MAX_PATH];
  static const WCHAR dircmdW[] = {'D','I','R','C','M','D','\0'};

  errorlevel = 0;

  /* Prefill quals with (uppercased) DIRCMD env var */
  if (GetEnvironmentVariableW(dircmdW, string, sizeof(string)/sizeof(WCHAR))) {
    p = string;
    while ( (*p = toupper(*p)) ) ++p;
    strcatW(string,quals);
    strcpyW(quals, string);
  }

  byte_total = 0;
  file_total = dir_total = 0;

  /* Initialize all flags to their defaults as if no DIRCMD or quals */
  paged_mode = FALSE;
  recurse    = FALSE;
  wide       = FALSE;
  bare       = FALSE;
  lower      = FALSE;
  shortname  = FALSE;
  usernames  = FALSE;
  orderByCol = FALSE;
  separator  = TRUE;
  dirTime = Written;
  dirOrder = Name;
  orderReverse = FALSE;
  orderGroupDirs = FALSE;
  orderGroupDirsReverse = FALSE;
  showattrs  = 0;
  attrsbits  = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;

  /* Handle args - Loop through so right most is the effective one */
  /* Note: /- appears to be a negate rather than an off, eg. dir
           /-W is wide, or dir /w /-w /-w is also wide             */
  p = quals;
  while (*p && (*p=='/' || *p==' ')) {
    BOOL negate = FALSE;
    if (*p++==' ') continue;  /* Skip / and blanks introduced through DIRCMD */

    if (*p=='-') {
      negate = TRUE;
      p++;
    }

    WINE_TRACE("Processing arg '%c' (in %s)\n", *p, wine_dbgstr_w(quals));
    switch (*p) {
    case 'P': if (negate) paged_mode = !paged_mode;
              else paged_mode = TRUE;
              break;
    case 'S': if (negate) recurse = !recurse;
              else recurse = TRUE;
              break;
    case 'W': if (negate) wide = !wide;
              else wide = TRUE;
              break;
    case 'B': if (negate) bare = !bare;
              else bare = TRUE;
              break;
    case 'L': if (negate) lower = !lower;
              else lower = TRUE;
              break;
    case 'X': if (negate) shortname = !shortname;
              else shortname = TRUE;
              break;
    case 'Q': if (negate) usernames = !usernames;
              else usernames = TRUE;
              break;
    case 'D': if (negate) orderByCol = !orderByCol;
              else orderByCol = TRUE;
              break;
    case 'C': if (negate) separator = !separator;
              else separator = TRUE;
              break;
    case 'T': p = p + 1;
              if (*p==':') p++;  /* Skip optional : */

              if (*p == 'A') dirTime = Access;
              else if (*p == 'C') dirTime = Creation;
              else if (*p == 'W') dirTime = Written;

              /* Support /T and /T: with no parms, default to written */
              else if (*p == 0x00 || *p == '/') {
                dirTime = Written;
                p = p - 1; /* So when step on, move to '/' */
              } else {
                SetLastError(ERROR_INVALID_PARAMETER);
                WCMD_print_error();
                errorlevel = 1;
                return;
              }
              break;
    case 'O': p = p + 1;
              if (*p==':') p++;  /* Skip optional : */
              while (*p && *p != '/') {
                WINE_TRACE("Processing subparm '%c' (in %s)\n", *p, wine_dbgstr_w(quals));
                switch (*p) {
                case 'N': dirOrder = Name;       break;
                case 'E': dirOrder = Extension;  break;
                case 'S': dirOrder = Size;       break;
                case 'D': dirOrder = Date;       break;
                case '-': if (*(p+1)=='G') orderGroupDirsReverse=TRUE;
                          else orderReverse = TRUE;
                          break;
                case 'G': orderGroupDirs = TRUE; break;
                default:
                    SetLastError(ERROR_INVALID_PARAMETER);
                    WCMD_print_error();
                    errorlevel = 1;
                    return;
                }
                p++;
              }
              p = p - 1; /* So when step on, move to '/' */
              break;
    case 'A': p = p + 1;
              showattrs = 0;
              attrsbits = 0;
              if (*p==':') p++;  /* Skip optional : */
              while (*p && *p != '/') {
                BOOL anegate = FALSE;
                ULONG mask;

                /* Note /A: - options are 'offs' not toggles */
                if (*p=='-') {
                  anegate = TRUE;
                  p++;
                }

                WINE_TRACE("Processing subparm '%c' (in %s)\n", *p, wine_dbgstr_w(quals));
                switch (*p) {
                case 'D': mask = FILE_ATTRIBUTE_DIRECTORY; break;
                case 'H': mask = FILE_ATTRIBUTE_HIDDEN;    break;
                case 'S': mask = FILE_ATTRIBUTE_SYSTEM;    break;
                case 'R': mask = FILE_ATTRIBUTE_READONLY;  break;
                case 'A': mask = FILE_ATTRIBUTE_ARCHIVE;   break;
                default:
                    SetLastError(ERROR_INVALID_PARAMETER);
                    WCMD_print_error();
                    errorlevel = 1;
                    return;
                }

                /* Keep running list of bits we care about */
                attrsbits |= mask;

                /* Mask shows what MUST be in the bits we care about */
                if (anegate) showattrs = showattrs & ~mask;
                else showattrs |= mask;

                p++;
              }
              p = p - 1; /* So when step on, move to '/' */
              WINE_TRACE("Result: showattrs %x, bits %x\n", showattrs, attrsbits);
              break;
    default:
              SetLastError(ERROR_INVALID_PARAMETER);
              WCMD_print_error();
              errorlevel = 1;
              return;
    }
    p = p + 1;
  }

  /* Handle conflicting args and initialization */
  if (bare || shortname) wide = FALSE;
  if (bare) shortname = FALSE;
  if (wide) usernames = FALSE;
  if (orderByCol) wide = TRUE;

  if (wide) {
      if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo))
          max_width = consoleInfo.dwSize.X;
      else
          max_width = 80;
  }
  if (paged_mode) {
     WCMD_enter_paged_mode(NULL);
  }

  argno         = 0;
  argN          = cmd;
  GetCurrentDirectoryW(MAX_PATH, cwd);
  strcatW(cwd, slashW);

  /* Loop through all args, calculating full effective directory */
  fullParms = NULL;
  prevEntry = NULL;
  while (argN) {
    WCHAR fullname[MAXSTRING];
    WCHAR *thisArg = WCMD_parameter(cmd, argno++, &argN, NULL);
    if (argN && argN[0] != '/') {

      WINE_TRACE("Found parm '%s'\n", wine_dbgstr_w(thisArg));
      if (thisArg[1] == ':' && thisArg[2] == '\\') {
        strcpyW(fullname, thisArg);
      } else if (thisArg[1] == ':' && thisArg[2] != '\\') {
        WCHAR envvar[4];
        static const WCHAR envFmt[] = {'=','%','c',':','\0'};
        wsprintfW(envvar, envFmt, thisArg[0]);
        if (!GetEnvironmentVariableW(envvar, fullname, MAX_PATH)) {
          static const WCHAR noEnvFmt[] = {'%','c',':','\0'};
          wsprintfW(fullname, noEnvFmt, thisArg[0]);
        }
        strcatW(fullname, slashW);
        strcatW(fullname, &thisArg[2]);
      } else if (thisArg[0] == '\\') {
        memcpy(fullname, cwd, 2 * sizeof(WCHAR));
        strcpyW(fullname+2, thisArg);
      } else {
        strcpyW(fullname, cwd);
        strcatW(fullname, thisArg);
      }
      WINE_TRACE("Using location '%s'\n", wine_dbgstr_w(fullname));

      status = GetFullPathNameW(fullname, sizeof(path)/sizeof(WCHAR), path, NULL);

      /*
       *  If the path supplied does not include a wildcard, and the endpoint of the
       *  path references a directory, we need to list the *contents* of that
       *  directory not the directory file itself.
       */
      if ((strchrW(path, '*') == NULL) && (strchrW(path, '%') == NULL)) {
        status = GetFileAttributesW(path);
        if ((status != INVALID_FILE_ATTRIBUTES) && (status & FILE_ATTRIBUTE_DIRECTORY)) {
          if (path[strlenW(path)-1] == '\\') {
            strcatW (path, starW);
          }
          else {
            static const WCHAR slashStarW[]  = {'\\','*','\0'};
            strcatW (path, slashStarW);
          }
        }
      } else {
        /* Special case wildcard search with no extension (ie parameters ending in '.') as
           GetFullPathName strips off the additional '.'                                  */
        if (fullname[strlenW(fullname)-1] == '.') strcatW(path, dotW);
      }

      WINE_TRACE("Using path '%s'\n", wine_dbgstr_w(path));
      thisEntry = HeapAlloc(GetProcessHeap(),0,sizeof(DIRECTORY_STACK));
      if (fullParms == NULL) fullParms = thisEntry;
      if (prevEntry != NULL) prevEntry->next = thisEntry;
      prevEntry = thisEntry;
      thisEntry->next = NULL;

      /* Split into components */
      WCMD_splitpath(path, drive, dir, fname, ext);
      WINE_TRACE("Path Parts: drive: '%s' dir: '%s' name: '%s' ext:'%s'\n",
                 wine_dbgstr_w(drive), wine_dbgstr_w(dir),
                 wine_dbgstr_w(fname), wine_dbgstr_w(ext));

      thisEntry->dirName = HeapAlloc(GetProcessHeap(),0,
                                     sizeof(WCHAR) * (strlenW(drive)+strlenW(dir)+1));
      strcpyW(thisEntry->dirName, drive);
      strcatW(thisEntry->dirName, dir);

      thisEntry->fileName = HeapAlloc(GetProcessHeap(),0,
                                     sizeof(WCHAR) * (strlenW(fname)+strlenW(ext)+1));
      strcpyW(thisEntry->fileName, fname);
      strcatW(thisEntry->fileName, ext);

    }
  }

  /* If just 'dir' entered, a '*' parameter is assumed */
  if (fullParms == NULL) {
    WINE_TRACE("Inserting default '*'\n");
    fullParms = HeapAlloc(GetProcessHeap(),0, sizeof(DIRECTORY_STACK));
    fullParms->next = NULL;
    fullParms->dirName = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (strlenW(cwd)+1));
    strcpyW(fullParms->dirName, cwd);
    fullParms->fileName = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * 2);
    strcpyW(fullParms->fileName, starW);
  }

  lastDrive = '?';
  prevEntry = NULL;
  thisEntry = fullParms;
  trailerReqd = FALSE;

  while (thisEntry != NULL) {

    /* Output disk free (trailer) and volume information (header) if the drive
       letter changes */
    if (lastDrive != toupper(thisEntry->dirName[0])) {

      /* Trailer Information */
      if (lastDrive != '?') {
        trailerReqd = FALSE;
        WCMD_dir_trailer(prevEntry->dirName[0]);
      }

      lastDrive = toupper(thisEntry->dirName[0]);

      if (!bare) {
         WCHAR drive[3];

         WINE_TRACE("Writing volume for '%c:'\n", thisEntry->dirName[0]);
         memcpy(drive, thisEntry->dirName, 2 * sizeof(WCHAR));
         drive[2] = 0x00;
         status = WCMD_volume (0, drive);
         trailerReqd = TRUE;
         if (!status) {
           errorlevel = 1;
           goto exit;
         }
      }
    } else {
      static const WCHAR newLine2[] = {'\n','\n','\0'};
      if (!bare) WCMD_output (newLine2);
    }

    /* Clear any errors from previous invocations, and process it */
    errorlevel = 0;
    prevEntry = thisEntry;
    thisEntry = WCMD_list_directory (thisEntry, 0);
  }

  /* Trailer Information */
  if (trailerReqd) {
    WCMD_dir_trailer(prevEntry->dirName[0]);
  }

exit:
  if (paged_mode) WCMD_leave_paged_mode();

  /* Free storage allocated for parms */
  while (fullParms != NULL) {
    prevEntry = fullParms;
    fullParms = prevEntry->next;
    HeapFree(GetProcessHeap(),0,prevEntry->dirName);
    HeapFree(GetProcessHeap(),0,prevEntry->fileName);
    HeapFree(GetProcessHeap(),0,prevEntry);
  }
}
示例#2
0
void WCMD_directory (void) {

char path[MAX_PATH], drive[8];
int status, paged_mode;
ULARGE_INTEGER avail, total, free;
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;

  byte_total = 0;
  file_total = dir_total = 0;

  /* Handle args */
  paged_mode = (strstr(quals, "/P") != NULL);
  recurse = (strstr(quals, "/S") != NULL);
  wide    = (strstr(quals, "/W") != NULL);
  bare    = (strstr(quals, "/B") != NULL);

  /* Handle conflicting args and initialization */
  if (bare) wide = FALSE;

  if (wide) {
      if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo))
          max_width = consoleInfo.dwSize.X;
      else
          max_width = 80;
  }
  if (paged_mode) {
     WCMD_enter_paged_mode();
  }

  if (param1[0] == '\0') strcpy (param1, ".");
  status = GetFullPathName (param1, sizeof(path), path, NULL);
  if (!status) {
    WCMD_print_error();
    if (paged_mode) WCMD_leave_paged_mode();
    return;
  }
  lstrcpyn (drive, path, 3);

  if (!bare) {
     status = WCMD_volume (0, drive);
     if (!status) {
         if (paged_mode) WCMD_leave_paged_mode();
       return;
     }
  }

  WCMD_list_directory (path, 0);
  lstrcpyn (drive, path, 4);
  GetDiskFreeSpaceEx (drive, &avail, &total, &free);

  if (!bare) {
     if (recurse) {
       WCMD_output ("\n\n     Total files listed:\n%8d files%25s bytes\n",
            file_total, WCMD_filesize64 (byte_total));
       WCMD_output ("%8d directories %18s bytes free\n\n",
            dir_total, WCMD_filesize64 (free.QuadPart));
     } else {
       WCMD_output (" %18s bytes free\n\n", WCMD_filesize64 (free.QuadPart));
     }
  }
  if (paged_mode) WCMD_leave_paged_mode();
}