Merge pull request #57 from henrygab/patch-6
Fix FAT bugs and increase file count limit
This commit is contained in:
		@@ -63,6 +63,7 @@
 | 
				
			|||||||
          <file file_name="../usb/uf2/uf2cfg.h" />
 | 
					          <file file_name="../usb/uf2/uf2cfg.h" />
 | 
				
			||||||
          <file file_name="../usb/uf2/uf2.h" />
 | 
					          <file file_name="../usb/uf2/uf2.h" />
 | 
				
			||||||
          <file file_name="../usb/uf2/ghostfat.c" />
 | 
					          <file file_name="../usb/uf2/ghostfat.c" />
 | 
				
			||||||
 | 
					          <file file_name="../usb/uf2/macros.h" />
 | 
				
			||||||
        </folder>
 | 
					        </folder>
 | 
				
			||||||
        <file file_name="../usb/msc_uf2.c" />
 | 
					        <file file_name="../usb/msc_uf2.c" />
 | 
				
			||||||
        <file file_name="../usb/usb.c" />
 | 
					        <file file_name="../usb/usb.c" />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					#include "macros.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "uf2.h"
 | 
					#include "uf2.h"
 | 
				
			||||||
#include "flash_nrf5x.h"
 | 
					#include "flash_nrf5x.h"
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
@@ -47,7 +49,6 @@ typedef struct {
 | 
				
			|||||||
    uint16_t startCluster;
 | 
					    uint16_t startCluster;
 | 
				
			||||||
    uint32_t size;
 | 
					    uint32_t size;
 | 
				
			||||||
} __attribute__((packed)) DirEntry;
 | 
					} __attribute__((packed)) DirEntry;
 | 
				
			||||||
 | 
					 | 
				
			||||||
STATIC_ASSERT(sizeof(DirEntry) == 32);
 | 
					STATIC_ASSERT(sizeof(DirEntry) == 32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct TextFile {
 | 
					struct TextFile {
 | 
				
			||||||
@@ -59,6 +60,7 @@ struct TextFile {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define STR0(x) #x
 | 
					#define STR0(x) #x
 | 
				
			||||||
#define STR(x) STR0(x)
 | 
					#define STR(x) STR0(x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char infoUf2File[] = //
 | 
					const char infoUf2File[] = //
 | 
				
			||||||
    "UF2 Bootloader " UF2_VERSION "\r\n"
 | 
					    "UF2 Bootloader " UF2_VERSION "\r\n"
 | 
				
			||||||
    "Model: " PRODUCT_NAME "\r\n"
 | 
					    "Model: " PRODUCT_NAME "\r\n"
 | 
				
			||||||
@@ -76,16 +78,27 @@ const char indexFile[] = //
 | 
				
			|||||||
    "</body>"
 | 
					    "</body>"
 | 
				
			||||||
    "</html>\n";
 | 
					    "</html>\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WARNING -- code presumes only one NULL .content for .UF2 file
 | 
				
			||||||
 | 
					//            and requires it be the last element of the array
 | 
				
			||||||
static struct TextFile const info[] = {
 | 
					static struct TextFile const info[] = {
 | 
				
			||||||
    {.name = "INFO_UF2TXT", .content = infoUf2File},
 | 
					    {.name = "INFO_UF2TXT", .content = infoUf2File},
 | 
				
			||||||
    {.name = "INDEX   HTM", .content = indexFile},
 | 
					    {.name = "INDEX   HTM", .content = indexFile},
 | 
				
			||||||
    {.name = "CURRENT UF2"},
 | 
					    {.name = "CURRENT UF2"},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
#define NUM_INFO (sizeof(info) / sizeof(info[0]))
 | 
					
 | 
				
			||||||
 | 
					// WARNING -- code presumes each non-UF2 file content fits in single sector
 | 
				
			||||||
 | 
					//            Cannot programmatically statically assert .content length
 | 
				
			||||||
 | 
					//            for each element above.
 | 
				
			||||||
 | 
					STATIC_ASSERT(ARRAY_SIZE2(indexFile) < 512);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NUM_FILES (ARRAY_SIZE2(info))
 | 
				
			||||||
 | 
					#define NUM_DIRENTRIES (NUM_FILES + 1) // Code adds volume label as first root directory entry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define UF2_SIZE           (current_flash_size() * 2)
 | 
					#define UF2_SIZE           (current_flash_size() * 2)
 | 
				
			||||||
#define UF2_SECTORS        (UF2_SIZE / 512)
 | 
					#define UF2_SECTORS        (UF2_SIZE / 512)
 | 
				
			||||||
#define UF2_FIRST_SECTOR   (NUM_INFO + 1)
 | 
					#define UF2_FIRST_SECTOR   (NUM_FILES + 1) // WARNING -- code presumes each non-UF2 file content fits in single sector
 | 
				
			||||||
#define UF2_LAST_SECTOR    (UF2_FIRST_SECTOR + UF2_SECTORS - 1)
 | 
					#define UF2_LAST_SECTOR    (UF2_FIRST_SECTOR + UF2_SECTORS - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RESERVED_SECTORS   1
 | 
					#define RESERVED_SECTORS   1
 | 
				
			||||||
@@ -97,6 +110,13 @@ static struct TextFile const info[] = {
 | 
				
			|||||||
#define START_ROOTDIR      (START_FAT1 + SECTORS_PER_FAT)
 | 
					#define START_ROOTDIR      (START_FAT1 + SECTORS_PER_FAT)
 | 
				
			||||||
#define START_CLUSTERS     (START_ROOTDIR + ROOT_DIR_SECTORS)
 | 
					#define START_CLUSTERS     (START_ROOTDIR + ROOT_DIR_SECTORS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// all directory entries must fit in a single sector
 | 
				
			||||||
 | 
					// because otherwise current code overflows buffer
 | 
				
			||||||
 | 
					#define DIRENTRIES_PER_SECTOR (512/sizeof(DirEntry))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					STATIC_ASSERT(NUM_DIRENTRIES < DIRENTRIES_PER_SECTOR * ROOT_DIR_SECTORS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static FAT_BootBlock const BootBlock = {
 | 
					static FAT_BootBlock const BootBlock = {
 | 
				
			||||||
    .JumpInstruction      = {0xeb, 0x3c, 0x90},
 | 
					    .JumpInstruction      = {0xeb, 0x3c, 0x90},
 | 
				
			||||||
    .OEMInfo              = "UF2 UF2 ",
 | 
					    .OEMInfo              = "UF2 UF2 ",
 | 
				
			||||||
@@ -104,7 +124,7 @@ static FAT_BootBlock const BootBlock = {
 | 
				
			|||||||
    .SectorsPerCluster    = 1,
 | 
					    .SectorsPerCluster    = 1,
 | 
				
			||||||
    .ReservedSectors      = RESERVED_SECTORS,
 | 
					    .ReservedSectors      = RESERVED_SECTORS,
 | 
				
			||||||
    .FATCopies            = 2,
 | 
					    .FATCopies            = 2,
 | 
				
			||||||
    .RootDirectoryEntries = (ROOT_DIR_SECTORS * 512 / 32),
 | 
					    .RootDirectoryEntries = (ROOT_DIR_SECTORS * DIRENTRIES_PER_SECTOR),
 | 
				
			||||||
    .TotalSectors16       = NUM_FAT_BLOCKS - 2,
 | 
					    .TotalSectors16       = NUM_FAT_BLOCKS - 2,
 | 
				
			||||||
    .MediaDescriptor      = 0xF8,
 | 
					    .MediaDescriptor      = 0xF8,
 | 
				
			||||||
    .SectorsPerFAT        = SECTORS_PER_FAT,
 | 
					    .SectorsPerFAT        = SECTORS_PER_FAT,
 | 
				
			||||||
@@ -191,7 +211,10 @@ void read_block(uint32_t block_no, uint8_t *data) {
 | 
				
			|||||||
            sectionIdx -= SECTORS_PER_FAT; // second FAT is same as the first...
 | 
					            sectionIdx -= SECTORS_PER_FAT; // second FAT is same as the first...
 | 
				
			||||||
        if (sectionIdx == 0) {
 | 
					        if (sectionIdx == 0) {
 | 
				
			||||||
            data[0] = 0xf8; // first FAT entry must match BPB MediaDescriptor
 | 
					            data[0] = 0xf8; // first FAT entry must match BPB MediaDescriptor
 | 
				
			||||||
            for (int i = 1; i < NUM_INFO * 2 + 4; ++i) {
 | 
					            // WARNING -- code presumes only one NULL .content for .UF2 file
 | 
				
			||||||
 | 
					            //            and all non-NULL .content fit in one sector
 | 
				
			||||||
 | 
					            //            and requires it be the last element of the array
 | 
				
			||||||
 | 
					            for (int i = 1; i < NUM_FILES * 2 + 4; ++i) {
 | 
				
			||||||
                data[i] = 0xff;
 | 
					                data[i] = 0xff;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -201,25 +224,48 @@ void read_block(uint32_t block_no, uint8_t *data) {
 | 
				
			|||||||
                ((uint16_t *)(void *)data)[i] = v == UF2_LAST_SECTOR ? 0xffff : v + 1;
 | 
					                ((uint16_t *)(void *)data)[i] = v == UF2_LAST_SECTOR ? 0xffff : v + 1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else if (block_no < START_CLUSTERS) { // Requested root directory sector
 | 
					    } else if (block_no < START_CLUSTERS) { // Requested root directory sector
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        sectionIdx -= START_ROOTDIR;
 | 
					        sectionIdx -= START_ROOTDIR;
 | 
				
			||||||
        if (sectionIdx == 0) { // only one sector of directory entries generated
 | 
					
 | 
				
			||||||
            DirEntry *d = (void *)data;
 | 
					        DirEntry *d = (void *)data;
 | 
				
			||||||
 | 
					        int remainingEntries = DIRENTRIES_PER_SECTOR;
 | 
				
			||||||
 | 
					        if (sectionIdx == 0) { // volume label first
 | 
				
			||||||
 | 
					            // volume label is first directory entry
 | 
				
			||||||
            padded_memcpy(d->name, (char const *) BootBlock.VolumeLabel, 11);
 | 
					            padded_memcpy(d->name, (char const *) BootBlock.VolumeLabel, 11);
 | 
				
			||||||
            d->attrs = 0x28;
 | 
					            d->attrs = 0x28;
 | 
				
			||||||
            for (int i = 0; i < NUM_INFO; ++i) {
 | 
					            d++;
 | 
				
			||||||
                d++;
 | 
					            remainingEntries--;
 | 
				
			||||||
                struct TextFile const *inf = &info[i];
 | 
					        }
 | 
				
			||||||
                d->size = inf->content ? strlen(inf->content) : UF2_SIZE;
 | 
					
 | 
				
			||||||
                d->startCluster = i + 2;
 | 
					        for (int i = DIRENTRIES_PER_SECTOR * sectionIdx;
 | 
				
			||||||
                padded_memcpy(d->name, inf->name, 11);
 | 
					             remainingEntries > 0 && i < NUM_FILES;
 | 
				
			||||||
			}
 | 
					             i++, d++) {
 | 
				
			||||||
		}
 | 
					
 | 
				
			||||||
    } else { // else Generate the UF2 file data on-the-fly
 | 
					            // WARNING -- code presumes all but last file take exactly one sector
 | 
				
			||||||
 | 
					            uint16_t startCluster = i + 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            struct TextFile const * inf = &info[i];
 | 
				
			||||||
 | 
					            padded_memcpy(d->name, inf->name, 11);
 | 
				
			||||||
 | 
					            d->createTimeFine   = __SECONDS_INT__ % 2 * 100;
 | 
				
			||||||
 | 
					            d->createTime       = __DOSTIME__;
 | 
				
			||||||
 | 
					            d->createDate       = __DOSDATE__;
 | 
				
			||||||
 | 
					            d->lastAccessDate   = __DOSDATE__;
 | 
				
			||||||
 | 
					            d->highStartCluster = startCluster >> 8;
 | 
				
			||||||
 | 
					            // DIR_WrtTime and DIR_WrtDate must be supported
 | 
				
			||||||
 | 
					            d->updateTime       = __DOSTIME__;
 | 
				
			||||||
 | 
					            d->updateDate       = __DOSDATE__;
 | 
				
			||||||
 | 
					            d->startCluster     = startCluster & 0xFF;
 | 
				
			||||||
 | 
					            // WARNING -- code presumes only one NULL .content for .UF2 file
 | 
				
			||||||
 | 
					            //            and requires it be the last element of the array
 | 
				
			||||||
 | 
					            d->size = inf->content ? strlen(inf->content) : UF2_SIZE;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
        sectionIdx -= START_CLUSTERS;
 | 
					        sectionIdx -= START_CLUSTERS;
 | 
				
			||||||
        if (sectionIdx < NUM_INFO - 1) {
 | 
					        if (sectionIdx < NUM_FILES - 1) {
 | 
				
			||||||
            memcpy(data, info[sectionIdx].content, strlen(info[sectionIdx].content));
 | 
					            memcpy(data, info[sectionIdx].content, strlen(info[sectionIdx].content));
 | 
				
			||||||
        } else {
 | 
					        } else { // generate the UF2 file data on-the-fly
 | 
				
			||||||
            sectionIdx -= NUM_INFO - 1;
 | 
					            sectionIdx -= NUM_FILES - 1;
 | 
				
			||||||
            uint32_t addr = USER_FLASH_START + sectionIdx * 256;
 | 
					            uint32_t addr = USER_FLASH_START + sectionIdx * 256;
 | 
				
			||||||
            if (addr < USER_FLASH_START+FLASH_SIZE) {
 | 
					            if (addr < USER_FLASH_START+FLASH_SIZE) {
 | 
				
			||||||
                UF2_Block *bl = (void *)data;
 | 
					                UF2_Block *bl = (void *)data;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										225
									
								
								src/usb/uf2/macros.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								src/usb/uf2/macros.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,225 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The MIT License (MIT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Copyright (c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be included in all
 | 
				
			||||||
 | 
					copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					SOFTWARE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef ARRAYSIZE2_H
 | 
				
			||||||
 | 
					#define ARRAYSIZE2_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __has_feature
 | 
				
			||||||
 | 
					    #define __has_feature(x) 0 // Compatibility with non-clang compilers.
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if __cplusplus >= 199711L
 | 
				
			||||||
 | 
					    #pragma message "using Ivan J. Johnson's ARRAY_SIZE2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Works on older compilers, even Visual C++ 6....
 | 
				
			||||||
 | 
					    // Created by Ivan J. Johnson, March 06, 2007
 | 
				
			||||||
 | 
					    // See http://drdobbs.com/cpp/197800525?pgno=1
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // Pseudocode:
 | 
				
			||||||
 | 
					    // if x is not an array
 | 
				
			||||||
 | 
					    //   issue a compile-time error
 | 
				
			||||||
 | 
					    // else
 | 
				
			||||||
 | 
					    //   use the traditional (non-typesafe) C99 COUNTOF expression
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // If the argument is any of:
 | 
				
			||||||
 | 
					    //    object of class type, such as an std::vector
 | 
				
			||||||
 | 
					    //    floating-point type
 | 
				
			||||||
 | 
					    //    function pointer
 | 
				
			||||||
 | 
					    //    pointer-to-member
 | 
				
			||||||
 | 
					    // then the first reinterpret_cast<> is not legal (compiler error)
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // The type for check1 is chosen and named to help understand
 | 
				
			||||||
 | 
					    // the cause of the error, because the class name is likely to
 | 
				
			||||||
 | 
					    // appear in the compiler error message.
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // If check1 succeeds, then the argument must be one of:
 | 
				
			||||||
 | 
					    //    an integral type
 | 
				
			||||||
 | 
					    //    an enumerated type
 | 
				
			||||||
 | 
					    //    a pointer to an object
 | 
				
			||||||
 | 
					    //    an array
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // Check2 expands approximately to sizeof(check_type(x, &x)),
 | 
				
			||||||
 | 
					    // where check_type is an overloaded function.
 | 
				
			||||||
 | 
					    // Because this is purely a compile-time computation,
 | 
				
			||||||
 | 
					    // the function is never really called or even implemented,
 | 
				
			||||||
 | 
					    // but it lets the compiler apply overload resolution,
 | 
				
			||||||
 | 
					    // which allows further type discrimination.
 | 
				
			||||||
 | 
					    // There are three possibilities to consider:
 | 
				
			||||||
 | 
					    //    x is an integral type or enumerated type.
 | 
				
			||||||
 | 
					    //      In this case, neither of the two function overloads
 | 
				
			||||||
 | 
					    //      is a match, resulting in a compiler error.
 | 
				
			||||||
 | 
					    //    x is a pointer to an object.
 | 
				
			||||||
 | 
					    //      In this case, the first argument to check_type()
 | 
				
			||||||
 | 
					    //      is a pointer and the second one is a pointer-to-pointer.
 | 
				
			||||||
 | 
					    //      The best function match is the first overload of check_type,
 | 
				
			||||||
 | 
					    //      the one that returns an incomplete type (Is_pointer).
 | 
				
			||||||
 | 
					    //      However, because Is_pointer is an incomplete type,
 | 
				
			||||||
 | 
					    //      sizeof(Is_pointer) is not a valid expression,
 | 
				
			||||||
 | 
					    //      resulting in a compiler error.
 | 
				
			||||||
 | 
					    //    x is an array.
 | 
				
			||||||
 | 
					    //      In this case, the first argument to check_type()
 | 
				
			||||||
 | 
					    //      is an array and the second is a pointer-to-array.
 | 
				
			||||||
 | 
					    //      A pointer-to-array is *NOT* convertible to a
 | 
				
			||||||
 | 
					    //      pointer-to-pointer, so the first overload of
 | 
				
			||||||
 | 
					    //      check_type() is not a match.
 | 
				
			||||||
 | 
					    //      However, an array IS convertible to a pointer,
 | 
				
			||||||
 | 
					    //      and a pointer-to-array already is a pointer.
 | 
				
			||||||
 | 
					    //      Any pointer is convertible to a void*,
 | 
				
			||||||
 | 
					    //      so the second function overload is a match.
 | 
				
			||||||
 | 
					    //      That overload returns a complete type (Is_array).
 | 
				
			||||||
 | 
					    //      Because it's a complete type,
 | 
				
			||||||
 | 
					    //      sizeof(Is_array) is a valid expression.
 | 
				
			||||||
 | 
					    // Thus, the compiler has EXCLUDED every possible type
 | 
				
			||||||
 | 
					    // except arrays via compilation errors before reaching
 | 
				
			||||||
 | 
					    // the third line.
 | 
				
			||||||
 | 
					    // Moreover, check1 and check2 are reduced to the value zero,
 | 
				
			||||||
 | 
					    // while the third line is the old type-unsafe C-style macro,
 | 
				
			||||||
 | 
					    // now made entirely type-safe.
 | 
				
			||||||
 | 
					    // 
 | 
				
			||||||
 | 
					    // Additional benefits:
 | 
				
			||||||
 | 
					    // The result is itself constexpr
 | 
				
			||||||
 | 
					    // 
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    #define ARRAY_SIZE2(arr) ( \
 | 
				
			||||||
 | 
					       0 * sizeof(reinterpret_cast<const ::Bad_arg_to_COUNTOF*>(arr)) + /*check1*/ \
 | 
				
			||||||
 | 
					       0 * sizeof(::Bad_arg_to_COUNTOF::check_type((arr), &(arr)))    + /*check2*/ \
 | 
				
			||||||
 | 
					       sizeof(arr) / sizeof((arr)[0])                                   /* eval */ \
 | 
				
			||||||
 | 
					       )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct Bad_arg_to_COUNTOF {
 | 
				
			||||||
 | 
					       class Is_pointer; // incomplete
 | 
				
			||||||
 | 
					       class Is_array {};
 | 
				
			||||||
 | 
					       template <typename T>
 | 
				
			||||||
 | 
					       static Is_pointer check_type(const T*, const T* const*);
 | 
				
			||||||
 | 
					       static Is_array check_type(const void*, const void*);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif __cplusplus >= 201103L ||  /* any compiler claiming C++11 support */ \
 | 
				
			||||||
 | 
					    _MSC_VER >= 1900 ||          /* Visual C++ 2015 or higher           */ \
 | 
				
			||||||
 | 
					    __has_feature(cxx_constexpr) /* CLang versions supporting constexp  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #pragma message "C++11 version ARRAY_SIZE2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    namespace detail
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        template <typename T, std::size_t N>
 | 
				
			||||||
 | 
					        constexpr std::size_t countof(T const (&)[N]) noexcept
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return N;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } // namespace detail
 | 
				
			||||||
 | 
					    #define ARRAY_SIZE2(arr) detail::countof(arr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif _MSC_VER // Visual C++ fallback
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #pragma message "using Microsoft Visual C++ intrinsic ARRAY_SIZE2"
 | 
				
			||||||
 | 
					    #define ARRAY_SIZE2(arr) _countof(arr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif __cplusplus >= 199711L && ( /* C++ 98 trick */ \
 | 
				
			||||||
 | 
					    defined(__INTEL_COMPILER) ||                     \
 | 
				
			||||||
 | 
					    defined(__clang__) ||                            \
 | 
				
			||||||
 | 
					    (defined(__GNUC__) && (                          \
 | 
				
			||||||
 | 
					        (__GNUC__ > 4) ||                            \
 | 
				
			||||||
 | 
					        (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)       \
 | 
				
			||||||
 | 
					    )))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #pragma message "C++98 version ARRAY_SIZE2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename T, std::size_t N>
 | 
				
			||||||
 | 
					    char(&_ArraySizeHelperRequiresArray(T(&)[N]))[N];
 | 
				
			||||||
 | 
					    #define ARRAY_SIZE2(x) sizeof(_ArraySizeHelperRequiresArray(x))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #pragma message "Using type-unsafe version of ARRAY_SIZE2"
 | 
				
			||||||
 | 
					    // This is the worst-case scenario macro.
 | 
				
			||||||
 | 
					    // While it is valid C, it is NOT typesafe.
 | 
				
			||||||
 | 
					    // For example, if the parameter arr is a pointer instead of array,
 | 
				
			||||||
 | 
					    // the compiler will SILENTLY give a (likely) incorrect result. 
 | 
				
			||||||
 | 
					    #define ARRAY_SIZE2(arr) sizeof(arr) / sizeof(arr[0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // ARRAYSIZE2_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef COMPILE_DATE_H
 | 
				
			||||||
 | 
					#define COMPILE_DATE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __YEAR_INT__ ((( \
 | 
				
			||||||
 | 
					  (__DATE__ [ 7u] - '0')  * 10u + \
 | 
				
			||||||
 | 
					  (__DATE__ [ 8u] - '0')) * 10u + \
 | 
				
			||||||
 | 
					  (__DATE__ [ 9u] - '0')) * 10u + \
 | 
				
			||||||
 | 
					  (__DATE__ [10u] - '0'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __MONTH_INT__ ( \
 | 
				
			||||||
 | 
					  (__DATE__ [2u] == 'n' && __DATE__ [1u] == 'a') ?  1u  /*Jan*/ \
 | 
				
			||||||
 | 
					: (__DATE__ [2u] == 'b'                        ) ?  2u  /*Feb*/ \
 | 
				
			||||||
 | 
					: (__DATE__ [2u] == 'r' && __DATE__ [1u] == 'a') ?  3u  /*Mar*/ \
 | 
				
			||||||
 | 
					: (__DATE__ [2u] == 'r'                        ) ?  4u  /*Apr*/ \
 | 
				
			||||||
 | 
					: (__DATE__ [2u] == 'y'                        ) ?  5u  /*May*/ \
 | 
				
			||||||
 | 
					: (__DATE__ [2u] == 'n'                        ) ?  6u  /*Jun*/ \
 | 
				
			||||||
 | 
					: (__DATE__ [2u] == 'l'                        ) ?  7u  /*Jul*/ \
 | 
				
			||||||
 | 
					: (__DATE__ [2u] == 'g'                        ) ?  8u  /*Jul*/ \
 | 
				
			||||||
 | 
					: (__DATE__ [2u] == 'p'                        ) ?  9u  /*Jul*/ \
 | 
				
			||||||
 | 
					: (__DATE__ [2u] == 't'                        ) ? 10u  /*Jul*/ \
 | 
				
			||||||
 | 
					: (__DATE__ [2u] == 'v'                        ) ? 11u  /*Jul*/ \
 | 
				
			||||||
 | 
					:                                                  12u  /*Dec*/ )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __DAY_INT__ ( \
 | 
				
			||||||
 | 
					   (__DATE__ [4u] == ' ' ? 0u : __DATE__ [4u] - '0') * 10u \
 | 
				
			||||||
 | 
					 + (__DATE__ [5u] - '0')                                   )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// __TIME__ expands to an eight-character string constant
 | 
				
			||||||
 | 
					// "23:59:01", or (if cannot determine time) "??:??:??" 
 | 
				
			||||||
 | 
					#define __HOUR_INT__ ( \
 | 
				
			||||||
 | 
					   (__TIME__ [0u] == '?' ? 0u : __TIME__ [0u] - '0') * 10u \
 | 
				
			||||||
 | 
					 + (__TIME__ [1u] == '?' ? 0u : __TIME__ [1u] - '0')       )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __MINUTE_INT__ ( \
 | 
				
			||||||
 | 
					   (__TIME__ [3u] == '?' ? 0u : __TIME__ [3u] - '0') * 10u \
 | 
				
			||||||
 | 
					 + (__TIME__ [4u] == '?' ? 0u : __TIME__ [4u] - '0')       )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __SECONDS_INT__ ( \
 | 
				
			||||||
 | 
					   (__TIME__ [6u] == '?' ? 0u : __TIME__ [6u] - '0') * 10u \
 | 
				
			||||||
 | 
					 + (__TIME__ [7u] == '?' ? 0u : __TIME__ [7u] - '0')       )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __DOSDATE__ ( \
 | 
				
			||||||
 | 
						((__YEAR_INT__  - 1980u) << 9u) | \
 | 
				
			||||||
 | 
						( __MONTH_INT__          << 5u) | \
 | 
				
			||||||
 | 
					                    ( __DAY_INT__            << 0u) )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __DOSTIME__ ( \
 | 
				
			||||||
 | 
						( __HOUR_INT__  << 11u) | \
 | 
				
			||||||
 | 
						( __MONTH_INT__ <<  5u) | \
 | 
				
			||||||
 | 
					                    ( __DAY_INT__   <<  0u) )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // COMPILE_DATE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Reference in New Issue
	
	Block a user