Writing "ls" under windows

Discussion in 'C Programming' started by jacob navia, Feb 21, 2014.

  1. jacob navia

    jacob navia Guest

    I am updating the examples about C programming for lcc-win, and I have
    developed a small example that lists the files in a given directory. It
    is very primitive, but it is just an example ofreusable code that you
    can change and/or incoporate into larger programs.

    Please feel free to comment, propose changes, etc.

    -----------------------------------------------cut here
    /* Print all the files in a directory that match a certain pattern.
    demonstrates: printf, FindFirstFile,FindNextFile,FindClose,
    FileTimeToLocalFileTime,FileTimeToSystemTime
    */
    #include <stdio.h>
    #include <stdlib.h>
    #include <windows.h>
    #include <string.h>
    static void printfile(WIN32_FIND_DATA *pdata,unsigned long long *pSize,
    unsigned *nrOfDirs,unsigned *nrOfFiles,unsigned attrib);
    static char *months[] = { "???",
    "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
    static int DecodeOptions(char *options)
    {
    int result = 0;

    if (*options == '/' || *options == '-')
    options++;
    strlwr(options);
    switch (*options) {
    case 'A':
    case 'a':
    options++;
    while (*options) {
    if (*options == 'd') {
    result |= FILE_ATTRIBUTE_DIRECTORY;
    options++;
    }
    if (*options == 'h') {
    result |= FILE_ATTRIBUTE_HIDDEN;
    options++;
    }
    if (*options == 's') {
    result |= FILE_ATTRIBUTE_SYSTEM;
    options++;
    }
    }
    break;
    }
    return result;
    }
    int main(int argc,char *argv[])
    {
    HANDLE handle;
    unsigned long long totalSize=0;
    unsigned int nrOfDirs=0;
    unsigned int nrOfFiles=0;
    WIN32_FIND_DATA data;
    char *pattern;
    int idx=1;
    unsigned attrib = 0;

    if (argc < 2) {
    pattern = "*.*";
    }
    else {
    if (argv[1][0]=='/' || argv[1][0]=='-') {
    attrib=DecodeOptions(argv[1]);
    idx++;
    }
    pattern = argv[idx];
    if (pattern == NULL)
    pattern = "*.*";
    }
    memset(&data,0,sizeof(data));
    /* find the first file that matches */
    if ((handle = FindFirstFile(pattern,&data)) ==
    INVALID_HANDLE_VALUE) {
    printf("No \"%s\" files found\n",pattern);
    return(-1);
    }
    /* print the pattern we received */
    printf("Listing of\t%s\n\n",pattern);
    /* print the first file specs */
    printfile(&data,&totalSize,&nrOfDirs,&nrOfFiles,attrib);
    /* loop finding all files that match */
    while (FindNextFile(handle,&data)) {
    printfile(&data,&totalSize,&nrOfDirs,&nrOfFiles,attrib);
    }
    if (GetLastError() != ERROR_NO_MORE_FILES) {
    printf("Unknown error %d\n",GetLastError());
    }
    FindClose(handle);
    if ((nrOfFiles+nrOfDirs) > 1) {
    if (nrOfDirs>0)
    printf("\tDirs:%d ",nrOfDirs);
    if (nrOfFiles>0)
    printf("files:%d ",nrOfFiles);
    if (totalSize > 0)
    printf(" Total (bytes):\t%'lld\n",totalSize);
    }
    return 0;
    }
    /* print the file specs and update some global counts */
    static void printfile(WIN32_FIND_DATA *pdata,unsigned long long *pSize,
    unsigned *nrDirs,unsigned *nrOfFiles, unsigned attrib)
    {
    FILETIME localFileTime;
    SYSTEMTIME SystemTime;
    long long siz;
    int isDir=0;

    /* ignore the . and .. entries */
    if (!strcmp(pdata->cFileName,".") || !strcmp(pdata->cFileName,".."))
    return;
    if (attrib && (attrib&pdata->dwFileAttributes)== 0)
    return;
    /* print some attributes */
    if (pdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
    printf("%-30s",pdata->cFileName);
    if (strlen(pdata->cFileName) > 29)
    printf("\n%36s"," <DIR>");
    else
    printf(" <DIR>");
    *nrDirs += 1;
    isDir=1;
    }
    else {
    printf("%-36s",pdata->cFileName);
    if (strlen(pdata->cFileName) > 35)
    printf("\n%36s"," ");
    *nrOfFiles+=1;
    }
    if (pdata->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
    printf("H");
    else printf(" ");
    if (pdata->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
    printf("S");
    else printf(" ");
    if (pdata->dwFileAttributes & FILE_ATTRIBUTE_READONLY)
    printf("R");
    else printf(" ");
    printf(" ");
    /* print the file size. */
    siz = ((long long) pdata->nFileSizeHigh << 32LL)|
    (long long)pdata->nFileSizeLow;
    if (isDir == 0) printf("%'12llu ",siz);
    else printf("%13s"," ");
    *pSize += siz;
    /* transform the file creation time to local file time */
    FileTimeToLocalFileTime(&pdata->ftLastWriteTime,&localFileTime);
    /* transform the local file time into a system time */
    FileTimeToSystemTime(&localFileTime,&SystemTime);
    /* print the time */
    printf("%4d %3s %02d %02d:%02d:%02d",
    SystemTime.wYear,months[SystemTime.wMonth],
    SystemTime.wDay,SystemTime.wHour,SystemTime.wMinute,
    SystemTime.wSecond);
    printf("\n");
    }
     
    jacob navia, Feb 21, 2014
    #1
    1. Advertisements

  2. Let me be the first - and to save Kiki and all his friends the trouble:

    Off topic. Not portable. Cant discuss it here. Blah, blah, blah.

    --
    Useful clc-related links:

    http://en.wikipedia.org/wiki/Aspergers
    http://en.wikipedia.org/wiki/Clique
    http://en.wikipedia.org/wiki/C_programming_language
     
    Kenny McCormack, Feb 21, 2014
    #2
    1. Advertisements

  3. In general, I'd have a good deal more space. It looks very cramped, and
    I can't tell what makes you use space sometimes and not others.
    I'd make the strings const.
    That limits the use -- you can't provide defaults by calling with string
    literal for example (then you can make the parameter const char *).
    Infinite loop when there's an unexpected option. I'd use another switch
    here are deal with the two cases as you did above.
    I'd move idx here. I went scanning to see where else it might be used
    and I would not have had to if it had had the smallest allowable scope.
    You might want to warn about unused command-line arguments.
    I presume that means something in Windows, but why the ()s?
    I'd write these as:

    putchar(pdata->dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 'R' : ' ');
    You don't need the LL and it's likely to confuse beginners.
    Does Windows not have some time formatting function?
     
    Ben Bacarisse, Feb 21, 2014
    #3
  4. jacob navia

    jacob navia Guest

    Le 21/02/2014 17:48, Ben Bacarisse a écrit :
    Infinite loop yes! You saw that bug!

    Thanks Ben (and for the other comments too)
     
    jacob navia, Feb 21, 2014
    #4
  5. jacob navia

    jacob navia Guest

    Le 21/02/2014 17:48, Ben Bacarisse a écrit :
    Apparently not. I googled several times about it and nothing appears,
    the msdn documentation remains silent about it. It is a pity because of
    course the format I use here is not universal (not adapted to locale
    conventions, for instance)

    strftime doesn't use a "SystemTime structure" but a "structure tm" that
    is very similar but not really equivalent. strftime would have
    eliminated the locale problem but I thought that the tedious
    tm.tm_year = SystemTimeStruct.year;
    tm.tm_month = SystemTimeStruct.month;

    etc... was not worth the effort.

    Obviously it is maybe a good idea to make a new addition to the lcc-win
    library with a function that converts one into the other for instance

    _Bool SystemTimeToStructureTM(SYSTEMTIME *,struct tm *);
    _Bool StructureTMToSystemTime(struct tm *,SYSTEMTIME *);

    Of course those functions would be tricky (as all this stuff) since days
    since January first in the structure tm needs to know everything about
    leap years and leap seconds, aaaaaaaargh!

    I will go on investigating this later.
     
    jacob navia, Feb 21, 2014
    #5
  6. jacob navia

    Ian Collins Guest

    Does Windows have mktime? If so, it should take care of the
    miscellaneous tm members. Try this:

    #include <stdio.h>
    #include <time.h>

    int main(void)
    {
    struct tm time = {0};

    time.tm_hour = 12;
    time.tm_mday = 22;
    time.tm_mon = 1;
    time.tm_year = 114;

    time_t then = mktime( &time );

    printf( "%d %d\n", time.tm_wday, time.tm_yday );
    return 0;
    }
     
    Ian Collins, Feb 21, 2014
    #6
  7. jacob navia

    Kaz Kylheku Guest

    As you know, Windows does not have a C library as part of the OS platform the
    way Unix-like systems do.

    However, there is a strftime function in the Microsoft C Run-time Library
    a.k.a. MSVCRT.DLL. This is the de-facto Windows counterpart of "libc".

    You can use this from from gcc-compiled source in the MinGW environment.

    Jacob's program could be rewritten to use functions like, opendir/readdir, stat
    and strftime under MinGW, producing a Windows executable that requires only
    MSVCRT.DLL, in addition to system DLL's.

    That same program could compile on Linux, MacOS, etc.

    The Windows API's could be used in it directly as necessary (for instance to
    access some Windows-specific file attributes), wrapped with #ifdefs.
     
    Kaz Kylheku, Feb 21, 2014
    #7
  8. jacob navia

    Kaz Kylheku Guest

    ???

    Google "msdn strftime". First hit.

    Ah, but I suppose you mean a time formatting function that isn't in the C
    run-time library, but in some core Win32 DLL, and that works with the
    Windows representations of time.

    But you can use LCC to develop programs that link with MSVCRT.DLL, right?
     
    Kaz Kylheku, Feb 21, 2014
    #8
  9. jacob navia

    jacob navia Guest

    Le 22/02/2014 00:20, Kaz Kylheku a écrit :
    MSVCRT.DLL doesn't exist any more since windows 64 bit came out (2005)

    Of course for 32 bit programs it could be used but it is at the standard
    of C 1989, not incoporating any of C 1999. I rewrote everything for the
    64 bit versions, and even in the 32 bit versions lcc-win doesn't use
    that any more.

    MINGW uses it, and it has countless bugs that we have discussed here
    several times since gcc for instance uses 80 bits long doubles and
    msvcrt.dll doesn't know about anything like 80 bits long doubles. For
    Microsoft long double is equal to double (what is accepted by the standard).

    Since the compiler and the run time library do not match you can't use
    printf to print a long double since the compiler generates a 12 bytes
    long double and Microsoft printf expects an 8 byte one.

    To avoid those bugs lcc-win uses its own printf, and most functions of
    the C99 library.

    For 64 bit windows the situation is very clear: MSVCRT.DLL doesn't exist
    anymore. So, I do not know what MINGW has done since it has been very
    difficult to obtain, install and run. I do not know if they have ported
    gcc's libc to windows, probably they now require cygwin or other strange
    software I do not know really.

    Coming back to our problem of a conversion I think I have developed a
    simple conversion function that I will present in a seprate message.

    jacob
     
    jacob navia, Feb 21, 2014
    #9
  10. jacob navia

    Geoff Guest

    This is absurd and completely false. The DLL is necessary for legacy
    program support and it is commonly distributed along with those
    programs and installed with them. The DLL exists in
    %systemroot%\system32 on all versions of Windows.
     
    Geoff, Feb 21, 2014
    #10
  11. jacob navia

    jacob navia Guest

    Le 22/02/2014 00:49, Geoff a écrit :
    Of course it exists. But you can't link any 64 bit programs with it
    since it is a 32 bit dll. It is there only for legacy applications and
    microsoft will never update it anymore
     
    jacob navia, Feb 21, 2014
    #11
  12. jacob navia

    Kaz Kylheku Guest

    Maybe Jacob means that it has no counterpart for 64 bit applications.
     
    Kaz Kylheku, Feb 22, 2014
    #12
  13. jacob navia

    Melzzzzz Guest

    You meant 10 bytes, I guess.
    Hm, they can't require cygwin as that would beat the purpose of mingw
    in the first place.
     
    Melzzzzz, Feb 22, 2014
    #13
  14. jacob navia

    jacob navia Guest

    Le 22/02/2014 01:06, Melzzzzz a écrit :
    No, the 10 bytes are rounded UP to 12 at least since if a 10 byte
    structure exists as a local variable in the stack, it leaves the stack
    unaligned what is really a catastrophe when it is pushed into the
    parameter area. So it MUST be a multiple of 4 under 32 bit systems and a
    multiple of 8 under 64 bit windows. This leads to lcc-win having 16 byte
    long doubles, wasting 6 bytes for each long double!

    Then, a pair of double precision numbers uses the same space as a single
    long double number. I developed a new module that uses a pair of doubles
    to implement numbers with around 30 digits precision.

    Much better than the 19 digits of FPU long doubles.
     
    jacob navia, Feb 22, 2014
    #14
  15. jacob navia

    Geoff Guest

    That is a far cry from "it doesn't exist anymore".
     
    Geoff, Feb 22, 2014
    #15
  16. jacob navia

    Melzzzzz Guest

    Same with Linux. With 32 bit executable reported size is 12 , with
    64 bit 16!
    You are absolutely right. I never used long double in program ;)
    There is also __float128 and accompanying library (libquadmath)
    in gcc. I never used those too ;)
     
    Melzzzzz, Feb 22, 2014
    #16
  17. jacob navia

    David Brown Guest

    This is one of the reasons for the mingw-64 fork - they have written
    their own C library (or ported an existing one - I don't know the
    details) to provide a decent, modern C library for both 32-bit and
    64-bit mingw compilers.

    (I haven't tried it myself - I just read about it after a previous
    thread here.)
     
    David Brown, Feb 22, 2014
    #17
  18. jacob navia

    Geoff Guest

    I don't know what Jacob means but the msvcrt.dll exists in
    C:\Windows\System32 directory on Windows 7/64 and it's 64-bit. The
    32-bit version is in C:\Windows\SysWOW64.
     
    Geoff, Feb 26, 2014
    #18
  19. CRT seems to be something evil the Microsoft have invented to try to break
    ANSI C.

    Does anyone know what it actually does?
     
    Malcolm McLean, Feb 26, 2014
    #19
  20. jacob navia

    jacob navia Guest

    Le 26/02/2014 08:48, Geoff a écrit :
    as I explained in another message in this same thread the dll exists,
    I do not discuss that, but it is a 32 bit dll that is no longer
    maintained by microsoft since at least 4-5 years and wikll be never
    maintained again. It is there for compatibility purposes only. It can't
    be used in any serious C99 compiler project.
     
    jacob navia, Feb 26, 2014
    #20
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.