Added Move constructor and bug fixes.

This commit is contained in:
Bill Greiman 2024-05-11 13:07:52 -07:00
parent 57900b21d2
commit aadedbf206
38 changed files with 500 additions and 175 deletions

View file

@ -1,13 +1,8 @@
### Warning: Major Reformat of Source in 2.2.2
File copy constructors and file assignment operators have been made private by
default in 2.2.3 to prevent call by value and multiple copies of file instances.
There are a huge number of changes in 2.2.2 since I decided to use clang-format
to force Google style formatting.
I did this to avoid warnings from the static analysis programs Cppcheck and
cpplint.
clang-format is aggressive so it may actually cause code to fail. For example
clang-format rearranges the order of includes according to the selected style.
SdFatConfig.h has options to make file constructors and assignment operators
public.
UTF-8 encoded filenames are supported in v2.1.0 or later.

Binary file not shown.

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2021 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License

View file

@ -6,7 +6,7 @@
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
#define SD_FAT_TYPE 3
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.

View file

@ -6,7 +6,7 @@
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
#define SD_FAT_TYPE 3
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.

View file

@ -5,7 +5,7 @@
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
#define SD_FAT_TYPE 3
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.

View file

@ -143,7 +143,7 @@ void loop() {
}
cout << F("\nCard successfully initialized.\n");
if (sd.vol()->fatType() == 0) {
cout << F("Can't find a valid FAT16/FAT32 partition.\n");
cout << F("Can't find a valid FAT16/FAT32/exFAT partition.\n");
reformatMsg();
return;
}
@ -163,7 +163,11 @@ void loop() {
cout << F("Card size: ") << sizeMB;
cout << F(" MB (MB = 1,000,000 bytes)\n");
cout << endl;
cout << F("Volume is FAT") << int(sd.vol()->fatType());
if (sd.fatType() <= 32) {
cout << F("\nVolume is FAT") << int(sd.fatType());
} else {
cout << F("\nVolume is exFAT");
}
cout << F(", Cluster size (bytes): ") << sd.vol()->bytesPerCluster();
cout << endl << endl;

View file

@ -2,7 +2,7 @@
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
#define SD_FAT_TYPE 3
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.

View file

@ -13,7 +13,7 @@
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
#define SD_FAT_TYPE 3
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.

View file

@ -1,5 +1,10 @@
/*
* This program attempts to initialize an SD card and analyze its structure.
* The CID and CSD registers are also printed in HEX for use in online
* decoders like these.
*
* https://gurumeditation.org/1342/sd-memory-card-register-decoder/
* https://archive.goughlui.com/static/multicid.htm
*/
#include "SdFat.h"
#include "sdios.h"
@ -55,7 +60,8 @@ void cidDmp() {
cout << F("Serial number: ") << hex << cid.psn() << dec << endl;
cout << F("Manufacturing date: ");
cout << cid.mdtMonth() << '/' << cid.mdtYear() << endl;
cout << endl;
cout << F("CID HEX: ");
hexDmp(&cid, sizeof(cid));
}
//------------------------------------------------------------------------------
void clearSerialInput() {
@ -69,7 +75,7 @@ void clearSerialInput() {
//------------------------------------------------------------------------------
void csdDmp() {
eraseSize = csd.eraseSize();
cout << F("cardSize: ") << 0.000512 * csd.capacity();
cout << F("\ncardSize: ") << 0.000512 * csd.capacity();
cout << F(" MB (MB = 1,000,000 bytes)\n");
cout << F("flashEraseSize: ") << int(eraseSize) << F(" blocks\n");
@ -85,6 +91,8 @@ void csdDmp() {
} else {
cout << F("zeros\n");
}
cout << F("CSD HEX: ");
hexDmp(&csd, sizeof(csd));
}
//------------------------------------------------------------------------------
void errorPrint() {
@ -96,10 +104,19 @@ void errorPrint() {
}
}
//------------------------------------------------------------------------------
void hexDmp(void* reg, uint8_t size) {
uint8_t* u8 = reinterpret_cast<uint8_t*>(reg);
cout << hex << noshowbase;
for (size_t i = 0; i < size; i++) {
cout << setw(2) << setfill('0') << int(u8[i]);
}
cout << dec << endl;
}
//------------------------------------------------------------------------------
bool mbrDmp() {
MbrSector_t mbr;
bool valid = true;
if (!sd.card()->readSector(0, (uint8_t *)&mbr)) {
if (!sd.card()->readSector(0, (uint8_t*)&mbr)) {
cout << F("\nread MBR failed.\n");
errorPrint();
return false;
@ -107,7 +124,7 @@ bool mbrDmp() {
cout << F("\nSD Partition Table\n");
cout << F("part,boot,bgnCHS[3],type,endCHS[3],start,length\n");
for (uint8_t ip = 1; ip < 5; ip++) {
MbrPart_t *pt = &mbr.part[ip - 1];
MbrPart_t* pt = &mbr.part[ip - 1];
if ((pt->boot != 0 && pt->boot != 0X80) ||
getLe32(pt->relativeSectors) > csd.capacity()) {
valid = false;
@ -242,7 +259,7 @@ void loop() {
printCardType();
cout << F("sdSpecVer: ") << 0.01 * scr.sdSpecVer() << endl;
cout << F("HighSpeedMode: ");
if (scr.sdSpecVer() && sd.card()->cardCMD6(0X00FFFFFF, cmd6Data) &&
if (scr.sdSpecVer() > 101 && sd.card()->cardCMD6(0X00FFFFFF, cmd6Data) &&
(2 & cmd6Data[13])) {
cout << F("true\n");
} else {

View file

@ -8,7 +8,7 @@
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
#define SD_FAT_TYPE 3
//
// Chip select may be constant or RAM variable.
const uint8_t SD_CS_PIN = 10;

View file

@ -0,0 +1,66 @@
// This is a simple SPI loop-back test.
//
// Connect SD_MISO to SD_MOSI
//
// Modify these defines for your configuration.
#define SD_SPI SPI
#define SD_MISO MISO
#define SD_MOSI MOSI
#include "SPI.h"
void setup() {
uint8_t rx, tx;
Serial.begin(9600);
while (!Serial) {
yield();
}
Serial.println(F("\nType any character to start"));
while (!Serial.available()) {
yield();
}
Serial.print("Begin, SD_MISO: ");
Serial.print(SD_MISO), Serial.print(", SD_MOSI: ");
Serial.println(SD_MOSI);
pinMode(SD_MISO, INPUT_PULLUP);
pinMode(SD_MOSI, OUTPUT);
digitalWrite(SD_MOSI, HIGH);
if (!digitalRead(SD_MISO)) {
Serial.println("Error: SD_MISO not HIGH");
goto fail;
}
digitalWrite(SD_MOSI, LOW);
if (digitalRead(SD_MISO)) {
Serial.println("Error: SD_MISO not LOW");
goto fail;
}
pinMode(SD_MISO, INPUT);
pinMode(SD_MOSI, INPUT);
// Modify if SD_SPI.begin has arguments and use this style SdFat begin call:
// sd.begin(SdSpiConfig(CS_PIN, USER_SPI_BEGIN | <other options>, &SD_SPI));
SD_SPI.begin();
// Start with a 400 kHz clock. Try full speed if success for 400 kHz.
SD_SPI.beginTransaction(SPISettings(400000, MSBFIRST, SPI_MODE0));
tx = 0;
do {
rx = SD_SPI.transfer(tx);
if (tx != rx) {
Serial.print("Error rx: 0x");
Serial.print(rx, HEX);
Serial.print(" != tx: 0x");
Serial.println(tx, HEX);
SD_SPI.endTransaction();
goto fail;
}
} while (tx++ < 255);
SD_SPI.endTransaction();
Serial.println("Success!");
return;
fail:
SD_SPI.endTransaction();
Serial.println("Is SD_MISO connected to SD_MOSI?");
Serial.println("Are SD_MISO and SD_MOSI correct?");
}
void loop() {}

View file

@ -1,13 +1,13 @@
/*
* This program is a simple binary write/read benchmark.
*/
#include "FreeStack.h"
#include "SdFat.h"
#include "FreeStack.h"
#include "sdios.h"
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
#define SD_FAT_TYPE 3
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.

View file

@ -6,7 +6,7 @@
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
#define SD_FAT_TYPE 3
/*
Change the value of SD_CS_PIN if you are using SPI and

11
extras/fmt_src.bat Normal file
View file

@ -0,0 +1,11 @@
clang-format --style=Google -i *.cpp *.h
rem clang-format --style=Google -i DigitalIO/*.h
rem clang-format --style=Google -i DigitalIO/boards/*.h
clang-format --style=Google -i common/*.cpp common/*.h
clang-format --style=Google -i ExFatLib/*.cpp ExFatLib/*.h
clang-format --style=Google -i FatLib/*.cpp FatLib/*.h
clang-format --style=Google -i FsLib/*.cpp FsLib/*.h
clang-format --style=Google -i iostream/*.cpp iostream/*.h
clang-format --style=Google -i SdCard/*.cpp SdCard/*.h
clang-format --style=Google -i SpiDriver/*.cpp SpiDriver/*.h
pause

View file

@ -1,5 +1,5 @@
name=SdFat
version=2.2.2
version=2.2.3
license=MIT
author=Bill Greiman <fat16lib@sbcglobal.net>
maintainer=Bill Greiman <fat16lib@sbcglobal.net>

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -223,7 +223,8 @@ bool ExFatFile::open(ExFatFile* dirFile, const char* path, oflag_t oflag) {
DBG_WARN_MACRO;
goto fail;
}
tmpDir = *this;
// tmpDir = *this;
tmpDir.copy(this);
dirFile = &tmpDir;
close();
}
@ -254,7 +255,8 @@ bool ExFatFile::openCwd() {
DBG_FAIL_MACRO;
goto fail;
}
*this = *ExFatVolume::cwv()->vwd();
// *this = *ExFatVolume::cwv()->vwd();
this->copy(ExFatVolume::cwv()->vwd());
rewind();
return true;

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -71,12 +71,78 @@ class ExFatFile {
*/
ExFatFile(const char* path, oflag_t oflag) { open(path, oflag); }
/** Copy from to this.
* \param[in] from Source file.
*/
void copy(const ExFatFile* from) {
if (from != this) {
#if FILE_COPY_CONSTRUCTOR_SELECT
*this = *from;
#else // FILE_COPY_CONSTRUCTOR_SELECT
memcpy(this, from, sizeof(ExFatFile));
#endif // FILE_COPY_CONSTRUCTOR_SELECT
}
}
/** move from to this.
* \param[in] from Source file.
*/
void move(ExFatFile* from) {
if (from != this) {
copy(from);
from->m_attributes = FILE_ATTR_CLOSED;
}
}
#if FILE_COPY_CONSTRUCTOR_SELECT == FILE_COPY_CONSTRUCTOR_PUBLIC
/** Copy constructor.
* \param[in] from Move from file.
*
*/
ExFatFile(const ExFatFile& from) = default;
/** Copy assignment operator.
* \param[in] from Move from file.
* \return Copied file.
*/
ExFatFile& operator=(const ExFatFile& from) = default;
#elif FILE_COPY_CONSTRUCTOR_SELECT == FILE_COPY_CONSTRUCTOR_PRIVATE
private:
ExFatFile(const ExFatFile& from) = default;
ExFatFile& operator=(const ExFatFile& from) = default;
public:
#else // FILE_COPY_CONSTRUCTOR_SELECT
ExFatFile(const ExFatFile& from) = delete;
ExFatFile& operator=(const ExFatFile& from) = delete;
#endif // FILE_COPY_CONSTRUCTOR_SELECT
#if FILE_MOVE_CONSTRUCTOR_SELECT
/** Move constructor.
* \param[in] from Move from file.
*/
ExFatFile(ExFatFile&& from) { move(&from); }
/** Move assignment operator.
* \param[in] from Move from file.
* \return Moved file.
*/
ExFatFile& operator=(ExFatFile&& from) {
move(&from);
return *this;
}
#else // FILE_MOVE_CONSTRUCTOR_SELECT
ExFatFile(ExFatFile&& from) = delete;
ExFatFile& operator=(ExFatFile&& from) = delete;
#endif
/** Destructor */
#if DESTRUCTOR_CLOSES_FILE
~ExFatFile() {
if (isOpen()) {
close();
}
}
#else // DESTRUCTOR_CLOSES_FILE
~ExFatFile() = default;
#endif // DESTRUCTOR_CLOSES_FILE
/** The parenthesis operator.
@ -223,7 +289,7 @@ class ExFatFile {
*
* \param[out] name An array of characters for the file's name.
* \param[in] size The size of the array in characters.
* \return the name length.
* \return length for success or zero for failure.
*/
size_t getName(char* name, size_t size) {
#if USE_UTF8_LONG_NAMES

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -179,7 +179,8 @@ bool ExFatFile::mkdir(ExFatFile* parent, const char* path, bool pFlag) {
goto fail;
}
}
tmpDir = *this;
// tmpDir = *this;
tmpDir.copy(this);
parent = &tmpDir;
close();
}
@ -312,7 +313,8 @@ bool ExFatFile::rename(ExFatFile* dirFile, const char* newPath) {
DBG_FAIL_MACRO;
goto fail;
}
oldFile = *this;
// oldFile = *this;
oldFile.copy(this);
m_dirPos = file.m_dirPos;
m_setCount = file.m_setCount;
m_flags |= FILE_FLAG_DIR_DIRTY;
@ -463,8 +465,9 @@ bool ExFatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
uint16_t time;
uint8_t ms10;
if (!isFile() || year < 1980 || year > 2107 || month < 1 || month > 12 ||
day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59) {
if (!isFileOrSubDir() || year < 1980 || year > 2107 || month < 1 ||
month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 ||
second > 59) {
DBG_FAIL_MACRO;
goto fail;
}

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -37,7 +37,8 @@ bool ExFatVolume::chdir(const char* path) {
DBG_FAIL_MACRO;
goto fail;
}
m_vwd = dir;
// m_vwd = dir;
m_vwd.copy(&dir);
return true;
fail:

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -354,7 +354,8 @@ bool FatFile::mkdir(FatFile* parent, const char* path, bool pFlag) {
goto fail;
}
}
tmpDir = *this;
// tmpDir = *this;
tmpDir.copy(this);
parent = &tmpDir;
close();
}
@ -477,7 +478,8 @@ bool FatFile::open(FatFile* dirFile, const char* path, oflag_t oflag) {
DBG_WARN_MACRO;
goto fail;
}
tmpDir = *this;
// tmpDir = *this;
tmpDir.copy(this);
dirFile = &tmpDir;
close();
}
@ -632,7 +634,8 @@ bool FatFile::openCwd() {
DBG_FAIL_MACRO;
goto fail;
}
*this = *FatVolume::cwv()->vwd();
// *this = *FatVolume::cwv()->vwd();
this->copy(FatVolume::cwv()->vwd());
rewind();
return true;
@ -965,7 +968,8 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) {
}
// sync() and cache directory entry
sync();
oldFile = *this;
// oldFile = *this;
oldFile.copy(this);
dir = cacheDirEntry(FsCache::CACHE_FOR_READ);
if (!dir) {
DBG_FAIL_MACRO;
@ -1281,8 +1285,9 @@ bool FatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
uint16_t dirTime;
DirFat_t* dir;
if (!isFile() || year < 1980 || year > 2107 || month < 1 || month > 12 ||
day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59) {
if (!isFileOrSubDir() || year < 1980 || year > 2107 || month < 1 ||
month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 ||
second > 59) {
DBG_FAIL_MACRO;
goto fail;
}

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -117,14 +117,80 @@ class FatFile {
* OR of open flags. see FatFile::open(FatFile*, const char*, uint8_t).
*/
FatFile(const char* path, oflag_t oflag) { open(path, oflag); }
#if DESTRUCTOR_CLOSES_FILE
/** Copy from to this.
* \param[in] from Source file.
*/
void copy(const FatFile* from) {
if (from != this) {
#if FILE_COPY_CONSTRUCTOR_SELECT
*this = *from;
#else // FILE_COPY_CONSTRUCTOR_SELECT
memcpy(this, from, sizeof(FatFile));
#endif // FILE_COPY_CONSTRUCTOR_SELECT
}
}
/** move from to this.
* \param[in] from Source file.
*/
void move(FatFile* from) {
if (from != this) {
copy(from);
from->m_attributes = FILE_ATTR_CLOSED;
}
}
#if FILE_COPY_CONSTRUCTOR_SELECT == FILE_COPY_CONSTRUCTOR_PUBLIC
/** Copy constructor.
* \param[in] from Move from file.
*
*/
FatFile(const FatFile& from) = default;
/** Copy assignment operator.
* \param[in] from Move from file.
* \return Copied file.
*/
FatFile& operator=(const FatFile& from) = default;
#elif FILE_COPY_CONSTRUCTOR_SELECT == FILE_COPY_CONSTRUCTOR_PRIVATE
private:
FatFile(const FatFile& from) = default;
FatFile& operator=(const FatFile& from) = default;
public:
#else // FILE_COPY_CONSTRUCTOR_SELECT
FatFile(const FatFile& from) = delete;
FatFile& operator=(const FatFile& from) = delete;
#endif // FILE_COPY_CONSTRUCTOR_SELECT
#if FILE_MOVE_CONSTRUCTOR_SELECT
/** Move constructor.
* \param[in] from Move from file.
*/
FatFile(FatFile&& from) { move(&from); }
/** Move assignment operator.
* \param[in] from Move from file.
* \return Moved file.
*/
FatFile& operator=(FatFile&& from) {
move(&from);
return *this;
}
#else // FILE_MOVE_CONSTRUCTOR_SELECT
FatFile(FatFile&& from) = delete;
FatFile& operator=(FatFile&& from) = delete;
#endif
/** Destructor */
#if DESTRUCTOR_CLOSES_FILE
~FatFile() {
if (isOpen()) {
close();
}
}
#else // DESTRUCTOR_CLOSES_FILE
~FatFile() = default;
#endif // DESTRUCTOR_CLOSES_FILE
/** The parenthesis operator.
*
* \return true if a file is open.
@ -323,8 +389,7 @@ class FatFile {
*
* \param[out] name An array of characters for the file's name.
* \param[in] size The size of the array in bytes. The array
* must be at least 13 bytes long. The file's name will be
* truncated if the file's name is too long.
* must be at least 13 bytes long.
* \return length for success or zero for failure.
*/
size_t getName(char* name, size_t size);
@ -333,7 +398,7 @@ class FatFile {
*
* \param[out] name An array of characters for the file's name.
* \param[in] size The size of the array in characters.
* \return the name length.
* \return length for success or zero for failure.
*/
size_t getName7(char* name, size_t size);
/**
@ -341,7 +406,7 @@ class FatFile {
*
* \param[out] name An array of characters for the file's name.
* \param[in] size The size of the array in characters.
* \return the name length.
* \return length for success or zero for failure.
*/
size_t getName8(char* name, size_t size);
#ifndef DOXYGEN_SHOULD_SKIP_THIS
@ -784,7 +849,7 @@ class FatFile {
*/
bool rename(FatFile* dirFile, const char* newPath);
/** Set the file's current position to zero. */
void rewind() { seekSet(0); }
void rewind() { seekSet(0UL); }
/** Remove a directory file.
*
* The directory file will be removed only if it is empty and is not the

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -54,7 +54,9 @@ static void putLfnChar(DirLfn_t* ldir, uint8_t i, uint16_t c) {
}
//==============================================================================
bool FatFile::cmpName(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd) {
FatFile dir = *this;
// FatFile dir = *this;
FatFile dir;
dir.copy(this);
DirLfn_t* ldir;
fname->reset();
for (uint8_t order = 1; order <= lfnOrd; order++) {
@ -92,7 +94,9 @@ fail:
}
//------------------------------------------------------------------------------
bool FatFile::createLFN(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd) {
FatFile dir = *this;
// FatFile dir = *this;
FatFile dir;
dir.copy(this);
DirLfn_t* ldir;
uint8_t checksum = lfnChecksum(fname->sfn);
uint8_t fc = 0;
@ -376,7 +380,6 @@ create:
if (freeFound == 0) {
freeIndex = curIndex;
}
while (freeFound < freeNeed) {
dir = dirFile->readDirCache();
if (!dir) {

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -156,7 +156,8 @@ bool FatFile::openExistingSFN(const char* path) {
if (*path == 0) {
return openRoot(vol);
}
*this = *vol->vwd();
// *this = *vol->vwd();
this->copy(vol->vwd());
do {
if (!parsePathName(path, &fname, &path)) {
DBG_FAIL_MACRO;
@ -183,7 +184,7 @@ bool FatFile::openSFN(FatSfn_t* fname) {
goto fail;
}
while (true) {
if (read(&dir, 32) != 32) {
if (read(&dir, sizeof(dir)) != sizeof(dir)) {
DBG_FAIL_MACRO;
goto fail;
}
@ -192,7 +193,7 @@ bool FatFile::openSFN(FatSfn_t* fname) {
goto fail;
}
if (isFatFileOrSubdir(&dir) && memcmp(fname->sfn, dir.name, 11) == 0) {
uint16_t saveDirIndex = (m_curPosition - 32) >> 5;
uint16_t saveDirIndex = (m_curPosition - sizeof(dir)) >> 5;
uint32_t saveDirCluster = m_firstCluster;
memset(this, 0, sizeof(FatFile));
m_attributes = dir.attributes & FS_ATTRIB_COPY;

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -37,7 +37,8 @@ bool FatVolume::chdir(const char* path) {
DBG_FAIL_MACRO;
goto fail;
}
m_vwd = dir;
// m_vwd = dir;
m_vwd.copy(&dir);
return true;
fail:

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -23,32 +23,36 @@
* DEALINGS IN THE SOFTWARE.
*/
#include "FsLib.h"
#if FILE_COPY_CONSTRUCTOR_SELECT
//------------------------------------------------------------------------------
FsBaseFile::FsBaseFile(const FsBaseFile& from) {
m_fFile = nullptr;
m_xFile = nullptr;
if (from.m_fFile) {
m_fFile = new (m_fileMem) FatFile;
*m_fFile = *from.m_fFile;
} else if (from.m_xFile) {
m_xFile = new (m_fileMem) ExFatFile;
*m_xFile = *from.m_xFile;
FsBaseFile::FsBaseFile(const FsBaseFile& from) { copy(&from); }
//------------------------------------------------------------------------------
FsBaseFile& FsBaseFile::operator=(const FsBaseFile& from) {
copy(&from);
return *this;
}
#endif // FILE_COPY_CONSTRUCTOR_SELECT
//------------------------------------------------------------------------------
void FsBaseFile::copy(const FsBaseFile* from) {
if (from != this) {
m_fFile = nullptr;
m_xFile = nullptr;
if (from->m_fFile) {
m_fFile = new (m_fileMem) FatFile;
m_fFile->copy(from->m_fFile);
} else if (from->m_xFile) {
m_xFile = new (m_fileMem) ExFatFile;
m_xFile->copy(from->m_xFile);
}
}
}
//------------------------------------------------------------------------------
FsBaseFile& FsBaseFile::operator=(const FsBaseFile& from) {
if (this == &from) {
return *this;
void FsBaseFile::move(FsBaseFile* from) {
if (from != this) {
copy(from);
from->m_fFile = nullptr;
from->m_xFile = nullptr;
}
close();
if (from.m_fFile) {
m_fFile = new (m_fileMem) FatFile;
*m_fFile = *from.m_fFile;
} else if (from.m_xFile) {
m_xFile = new (m_fileMem) ExFatFile;
*m_xFile = *from.m_xFile;
}
return *this;
}
//------------------------------------------------------------------------------
bool FsBaseFile::close() {

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -49,9 +49,18 @@ class FsBaseFile {
*/
FsBaseFile(const char* path, oflag_t oflag) { open(path, oflag); }
~FsBaseFile() { close(); }
/** Copy from to this.
* \param[in] from Source file.
*/
void copy(const FsBaseFile* from);
/** move from to this.
* \param[in] from Source file.
*/
void move(FsBaseFile* from);
#if FILE_COPY_CONSTRUCTOR_SELECT == FILE_COPY_CONSTRUCTOR_PUBLIC
/** Copy constructor.
*
* \param[in] from Object used to initialize this instance.
*/
FsBaseFile(const FsBaseFile& from);
@ -60,6 +69,46 @@ class FsBaseFile {
* \return assigned object.
*/
FsBaseFile& operator=(const FsBaseFile& from);
#elif FILE_COPY_CONSTRUCTOR_SELECT == FILE_COPY_CONSTRUCTOR_PRIVATE
private:
FsBaseFile(const FsBaseFile& from);
FsBaseFile& operator=(const FsBaseFile& from);
public:
#else // FILE_COPY_CONSTRUCTOR_SELECT
FsBaseFile(const FsBaseFile& from) = delete;
FsBaseFile& operator=(const FsBaseFile& from) = delete;
#endif // FILE_COPY_CONSTRUCTOR_SELECT
#if FILE_MOVE_CONSTRUCTOR_SELECT
/** Move constructor.
* \param[in] from File to move.
*/
FsBaseFile(FsBaseFile&& from) { move(&from); }
/** Move assignment operator.
* \param[in] from File to move.
* \return Assigned file.
*/
FsBaseFile& operator=(FsBaseFile&& from) {
move(&from);
return *this;
}
#else // FILE_MOVE_CONSTRUCTOR_SELECT
FsBaseFile(FsBaseFile&& from) = delete;
FsBaseFile& operator=(FsBaseFile&& from) = delete;
#endif // FILE_MOVE_CONSTRUCTOR_SELECT
#if DESTRUCTOR_CLOSES_FILE
~FsBaseFile() {
if (isOpen()) {
close();
}
}
#else // DESTRUCTOR_CLOSES_FILE
~FsBaseFile() = default;
#endif // DESTRUCTOR_CLOSES_FILE
/** The parenthesis operator.
*
* \return true if a file is open.
@ -752,7 +801,7 @@ class FsBaseFile {
* \return true for success or false for failure.
*/
bool seekSet(uint64_t pos) {
return m_fFile ? pos < (1ULL << 32) && m_fFile->seekSet(pos)
return m_fFile ? pos < (1ULL << 32) && m_fFile->seekSet((uint32_t)pos)
: m_xFile ? m_xFile->seekSet(pos)
: false;
}

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -64,11 +64,10 @@ class SdCardFactory {
/** Initialize SPI card.
*
* \param[in] config SPI configuration.
* \return generic card pointer.
* \return generic card pointer or nullptr if failure.
*/
SdCard* newCard(SdSpiConfig config) {
m_spiCard.begin(config);
return &m_spiCard;
return m_spiCard.begin(config) ? &m_spiCard : nullptr;
}
/** Initialize SDIO card.
*
@ -77,8 +76,7 @@ class SdCardFactory {
*/
SdCard* newCard(SdioConfig config) {
#if HAS_SDIO_CLASS
m_sdioCard.begin(config);
return &m_sdioCard;
return m_sdioCard.begin(config) ? &m_sdioCard : nullptr;
#else // HAS_SDIO_CLASS
(void)config;
return nullptr;

View file

@ -59,7 +59,7 @@
SD_CARD_ERROR(CMD8, "Send and check interface settings") \
SD_CARD_ERROR(CMD9, "Read CSD data") \
SD_CARD_ERROR(CMD10, "Read CID data") \
SD_CARD_ERROR(CMD12, "Stop multiple block read") \
SD_CARD_ERROR(CMD12, "Stop multiple block transmission") \
SD_CARD_ERROR(CMD13, "Read card status") \
SD_CARD_ERROR(CMD17, "Read single block") \
SD_CARD_ERROR(CMD18, "Read multiple blocks") \

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -59,6 +59,8 @@ class SdCardInterface : public FsBlockDeviceInterface {
virtual bool hasDedicatedSpi() { return false; }
/** \return false by default */
bool virtual isDedicatedSpi() { return false; }
/** \return false by default */
bool virtual isSpi() { return false; }
/** Set SPI sharing state
* \param[in] value desired state.
* \return false by default.

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -123,6 +123,8 @@ static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
// SharedSpiCard member functions
//------------------------------------------------------------------------------
bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
uint8_t cardType;
uint32_t arg;
Timeout timeout;
// Restore state to creator.
initSharedSpiCard();
@ -140,7 +142,7 @@ bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
spiSetSckSpeed(1000UL * SD_MAX_INIT_RATE_KHZ);
spiBegin(spiConfig);
m_beginCalled = true;
uint32_t arg;
spiStart();
// must supply min of 74 clock cycles with CS high.
@ -169,7 +171,7 @@ bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
// check SD version
while (true) {
if (cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND) {
type(SD_CARD_TYPE_SD1);
cardType = SD_CARD_TYPE_SD1;
break;
}
// Skip first three bytes.
@ -177,7 +179,7 @@ bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
m_status = spiReceive();
}
if (m_status == 0XAA) {
type(SD_CARD_TYPE_SD2);
cardType = SD_CARD_TYPE_SD2;
break;
}
if (timeout.timedOut()) {
@ -186,7 +188,7 @@ bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
}
}
// initialize card and send host supports SDHC if SD2
arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
arg = cardType == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
while (cardAcmd(ACMD41, arg) != R1_READY_STATE) {
// check for timeout
if (timeout.timedOut()) {
@ -195,13 +197,13 @@ bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
}
}
// if SD2 read OCR register to check for SDHC card
if (type() == SD_CARD_TYPE_SD2) {
if (cardType == SD_CARD_TYPE_SD2) {
if (cardCommand(CMD58, 0)) {
error(SD_CARD_ERROR_CMD58);
goto fail;
}
if ((spiReceive() & 0XC0) == 0XC0) {
type(SD_CARD_TYPE_SDHC);
cardType = SD_CARD_TYPE_SDHC;
}
// Discard rest of ocr - contains allowed voltage range.
for (uint8_t i = 0; i < 3; i++) {
@ -210,6 +212,7 @@ bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
}
spiStop();
spiSetSckSpeed(spiConfig.maxSck);
m_type = cardType;
return true;
fail:
@ -307,7 +310,7 @@ bool SharedSpiCard::erase(uint32_t firstSector, uint32_t lastSector) {
goto fail;
}
}
if (m_type != SD_CARD_TYPE_SDHC) {
if (type() != SD_CARD_TYPE_SDHC) {
firstSector <<= 9;
lastSector <<= 9;
}

View file

@ -141,6 +141,8 @@ class SharedSpiCard {
bool isBusy();
/** \return false, can't be in dedicated state. */
bool isDedicatedSpi() { return false; }
/** \return true if card is on SPI bus. */
bool isSpi() { return true; }
/**
* Read a card's CID register. The CID contains card identification
* information such as Manufacturer ID, Product name, Product serial
@ -301,7 +303,6 @@ class SharedSpiCard {
void spiStart();
void spiStop();
void spiUnselect() { sdCsWrite(m_csPin, true); }
void type(uint8_t value) { m_type = value; }
bool waitReady(uint16_t ms);
bool writeData(uint8_t token, const uint8_t* src);
#if SPI_DRIVER_SELECT < 2

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -176,21 +176,11 @@ class SdioCard : public SdCardInterface {
* \param[in] sector Address of first sector in sequence.
*
* \note This function is used with readData() and readStop() for optimized
* multiple sector reads. SPI chipSelect must be low for the entire sequence.
* multiple sector reads.
*
* \return true for success or false for failure.
*/
bool readStart(uint32_t sector);
/** Start a read multiple sectors sequence.
*
* \param[in] sector Address of first sector in sequence.
* \param[in] count Maximum sector count.
* \note This function is used with readData() and readStop() for optimized
* multiple sector reads. SPI chipSelect must be low for the entire sequence.
*
* \return true for success or false for failure.
*/
bool readStart(uint32_t sector, uint32_t count);
/** End a read multiple sectors sequence.
*
* \return true for success or false for failure.
@ -251,16 +241,6 @@ class SdioCard : public SdCardInterface {
* \return true for success or false for failure.
*/
bool writeStart(uint32_t sector);
/** Start a write multiple sectors sequence.
*
* \param[in] sector Address of first sector in sequence.
* \param[in] count Maximum sector count.
* \note This function is used with writeData() and writeStop()
* for optimized multiple sector writes.
*
* \return true for success or false for failure.
*/
bool writeStart(uint32_t sector, uint32_t count);
/** End a write multiple sectors sequence.
*

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -764,11 +764,23 @@ bool SdioCard::begin(SdioConfig sdioConfig) {
// Determine if High Speed mode is supported and set frequency.
// Check status[16] for error 0XF or status[16] for new mode 0X1.
uint8_t status[64];
if (m_scr.sdSpec() > 0 && cardCMD6(0X00FFFFFF, status) && (2 & status[13]) &&
cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) {
kHzSdClk = 50000;
} else {
kHzSdClk = 25000;
kHzSdClk = 25000;
if (m_scr.sdSpec() > 0) {
// card is 1.10 or greater - must support CMD6
if (!cardCMD6(0X00FFFFFF, status)) {
return false;
}
if (2 & status[13]) {
// Card supports High Speed mode - switch mode.
if (!cardCMD6(0X80FFFFF1, status)) {
return false;
}
if ((status[16] & 0XF) == 1) {
kHzSdClk = 50000;
} else {
return sdError(SD_CARD_ERROR_CMD6);
}
}
}
// Disable GPIO.
enableGPIO(false);
@ -1036,8 +1048,10 @@ bool SdioCard::syncDevice() {
}
//------------------------------------------------------------------------------
uint8_t SdioCard::type() const {
return m_version2 ? m_highCapacity ? SD_CARD_TYPE_SDHC : SD_CARD_TYPE_SD2
: SD_CARD_TYPE_SD1;
return !m_initDone ? 0
: !m_version2 ? SD_CARD_TYPE_SD1
: !m_highCapacity ? SD_CARD_TYPE_SD2
: SD_CARD_TYPE_SDHC;
}
//------------------------------------------------------------------------------
bool SdioCard::writeData(const uint8_t* src) {

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -38,9 +38,9 @@
#endif // INCLUDE_SDIOS
//------------------------------------------------------------------------------
/** SdFat version for cpp use. */
#define SD_FAT_VERSION 20202
#define SD_FAT_VERSION 20203
/** SdFat version as string. */
#define SD_FAT_VERSION_STR "2.2.2"
#define SD_FAT_VERSION_STR "2.2.3"
//==============================================================================
/**
* \class SdBase
@ -80,7 +80,7 @@ class SdBase : public Vol {
* \return true for success or false for failure.
*/
bool begin(SdSpiConfig spiConfig) {
return cardBegin(spiConfig) && Vol::begin(m_card);
return cardBegin(spiConfig) && volumeBegin();
}
//---------------------------------------------------------------------------
/** Initialize SD card and file system for SDIO mode.
@ -89,7 +89,7 @@ class SdBase : public Vol {
* \return true for success or false for failure.
*/
bool begin(SdioConfig sdioConfig) {
return cardBegin(sdioConfig) && Vol::begin(m_card);
return cardBegin(sdioConfig) && volumeBegin();
}
//----------------------------------------------------------------------------
/** \return Pointer to SD card object. */
@ -347,7 +347,9 @@ class SdBase : public Vol {
*
* \return true for success or false for failure.
*/
bool volumeBegin() { return Vol::begin(m_card); }
bool volumeBegin() {
return Vol::begin(m_card) || Vol::begin(m_card, true, 0);
}
#if ENABLE_ARDUINO_SERIAL
/** Print error details after begin() fails. */
void initErrorPrint() { initErrorPrint(&Serial); }
@ -445,7 +447,6 @@ typedef FsBaseFile SdBaseFile;
#if defined __has_include
#if __has_include(<FS.h>)
#define HAS_INCLUDE_FS_H
#warning File not defined because __has_include(FS.h)
#endif // __has_include(<FS.h>)
#endif // defined __has_include
#ifndef HAS_INCLUDE_FS_H
@ -457,6 +458,8 @@ typedef ExFile File;
#elif SDFAT_FILE_TYPE == 3
typedef FsFile File;
#endif // SDFAT_FILE_TYPE
#elif !defined(DISABLE_FS_H_WARNING)
#warning File not defined because __has_include(FS.h)
#endif // HAS_INCLUDE_FS_H
/**
* \class SdFile

View file

@ -1,5 +1,5 @@
/**
* Copyright (c) 2011-2022 Bill Greiman
* Copyright (c) 2011-2024 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
@ -34,7 +34,7 @@
#endif // __AVR__
//
// To try UTF-8 encoded filenames.
// #define USE_UTF8_LONG_NAMES 1
// #define USE_UTF8_LONG_NAMES 1
//
// For minimum flash size use these settings:
// #define USE_FAT_FILE_FLAG_CONTIGUOUS 0
@ -46,6 +46,48 @@
// Options can be set in a makefile or an IDE like platformIO
// if they are in a #ifndef/#endif block below.
//------------------------------------------------------------------------------
/*
* Options for file class constructors, assignment operators and destructors.
*
* By default file copy constructors and copy assignment operators are
* private to prevent multiple copies of a instance for a file.
*
* File move constructors and move assignment operators are public to permit
* return of a file instance for compilers that aren't able to use copy elision.
*
*/
/** File copy constructors and copy assignment operators are deleted */
#define FILE_COPY_CONSTRUCTOR_DELETED 0
/** File copy constructors and copy assignment operators are private */
#define FILE_COPY_CONSTRUCTOR_PRIVATE 1
/** File copy constructors and copy assignment operators are public */
#define FILE_COPY_CONSTRUCTOR_PUBLIC 2
#ifndef FILE_COPY_CONSTRUCTOR_SELECT
/** Specify kind of file copy constructors and copy assignment operators */
#define FILE_COPY_CONSTRUCTOR_SELECT FILE_COPY_CONSTRUCTOR_PRIVATE
#endif // FILE_COPY_CONSTRUCTOR_SELECT
/** File move constructors and move assignment operators are deleted. */
#define FILE_MOVE_CONSTRUCTOR_DELETED 0
/** File move constructors and move assignment operators are public. */
#define FILE_MOVE_CONSTRUCTOR_PUBLIC 1
#ifndef FILE_MOVE_CONSTRUCTOR_SELECT
/** Specify kind of file move constructors and move assignment operators */
#define FILE_MOVE_CONSTRUCTOR_SELECT FILE_MOVE_CONSTRUCTOR_PUBLIC
#endif // FILE_MOVE_CONSTRUCTOR_SELECT
#if FILE_MOVE_CONSTRUCTOR_SELECT != FILE_MOVE_CONSTRUCTOR_PUBLIC && \
FILE_COPY_CONSTRUCTOR_SELECT != FILE_COPY_CONSTRUCTOR_PUBLIC
#error "No public move or copy assign operators"
#endif // FILE_MOVE_CONSTRUCTOR_SELECT && FILE_MOVE_CONSTRUCTOR_SELECT
/**
* Set DESTRUCTOR_CLOSES_FILE nonzero to close a file in its destructor. */
#ifndef DESTRUCTOR_CLOSES_FILE
#define DESTRUCTOR_CLOSES_FILE 0
#endif // DESTRUCTOR_CLOSES_FILE
//------------------------------------------------------------------------------
/** For Debug - must be one */
#define ENABLE_ARDUINO_FEATURES 1
/** For Debug - must be one */
@ -327,15 +369,6 @@ typedef uint8_t SdCsPin_t;
#define FAT12_SUPPORT 0
#endif // FAT12_SUPPORT
//------------------------------------------------------------------------------
/**
* Set DESTRUCTOR_CLOSES_FILE nonzero to close a file in its destructor.
*
* Causes use of lots of heap in ARM.
*/
#ifndef DESTRUCTOR_CLOSES_FILE
#define DESTRUCTOR_CLOSES_FILE 0
#endif // DESTRUCTOR_CLOSES_FILE
//------------------------------------------------------------------------------
/**
* Call flush for endl if ENDL_CALLS_FLUSH is nonzero
*

View file

@ -33,30 +33,25 @@ constexpr uint16_t compileYear() {
return 1000 * (__DATE__[7] - '0') + 100 * (__DATE__[8] - '0') +
10 * (__DATE__[9] - '0') + (__DATE__[10] - '0');
}
/** \return true if str equals the month field of the __DATE__ macro. */
constexpr bool compileMonthIs(const char* str) {
return __DATE__[0] == str[0] && __DATE__[1] == str[1] &&
__DATE__[2] == str[2];
}
/** \return month field of the __DATE__ macro. */
constexpr uint8_t compileMonth() {
return compileMonthIs("Jan") ? 1
: compileMonthIs("Feb") ? 2
: compileMonthIs("Mar") ? 3
: compileMonthIs("Apr") ? 4
: compileMonthIs("May") ? 5
: compileMonthIs("Jun") ? 6
: compileMonthIs("Jul") ? 7
: compileMonthIs("Aug") ? 8
: compileMonthIs("Sep") ? 9
: compileMonthIs("Oct") ? 10
: compileMonthIs("Nov") ? 11
: compileMonthIs("Dec") ? 12
: 0;
return __DATE__[0] == 'J' && __DATE__[1] == 'a' && __DATE__[2] == 'n' ? 1
: __DATE__[0] == 'F' && __DATE__[1] == 'e' && __DATE__[2] == 'b' ? 2
: __DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'r' ? 3
: __DATE__[0] == 'A' && __DATE__[1] == 'p' && __DATE__[2] == 'r' ? 4
: __DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'y' ? 5
: __DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'n' ? 6
: __DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'l' ? 7
: __DATE__[0] == 'A' && __DATE__[1] == 'u' && __DATE__[2] == 'g' ? 8
: __DATE__[0] == 'S' && __DATE__[1] == 'e' && __DATE__[2] == 'p' ? 9
: __DATE__[0] == 'O' && __DATE__[1] == 'c' && __DATE__[2] == 't' ? 10
: __DATE__[0] == 'N' && __DATE__[1] == 'o' && __DATE__[2] == 'v' ? 11
: __DATE__[0] == 'D' && __DATE__[1] == 'e' && __DATE__[2] == 'c' ? 12
: 0;
}
/** \return day field of the __DATE__ macro. */
constexpr uint8_t compileDay() {
return 10 * (__DATE__[4] == ' ' ? 0 : __DATE__[4] - '0') +
return 10 * ((__DATE__[4] == ' ' ? '0' : __DATE__[4]) - '0') +
(__DATE__[5] - '0');
}
/** \return hour field of the __TIME__ macro. */

View file

@ -201,7 +201,10 @@ int StdioStream::fseek(int32_t offset, int origin) {
break;
case SEEK_SET:
if (!StreamBaseFile::seekSet(offset)) {
if (offset < 0) {
goto fail;
}
if (!StreamBaseFile::seekSet((uint32_t)offset)) {
goto fail;
}
break;
@ -349,7 +352,7 @@ bool StdioStream::rewind() {
return false;
}
}
StreamBaseFile::seekSet(0);
StreamBaseFile::seekSet(0UL);
m_r = 0;
return true;
}