/* Arduino SdFat Library * Copyright (C) 2012 by William Greiman * * This file is part of the Arduino SdFat Library * * This Library is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This Library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with the Arduino SdFat Library. If not, see * . */ #include #include //------------------------------------------------------------------------------ /** List directory contents to stdOut. * * \param[in] flags The inclusive OR of * * LS_DATE - %Print file modification date * * LS_SIZE - %Print file size. * * LS_R - Recursive list of subdirectories. */ void SdBaseFile::ls(uint8_t flags) { ls(SdFat::stdOut(), flags, 0); } //------------------------------------------------------------------------------ /** List directory contents. * * \param[in] pr Print stream for list. * * \param[in] flags The inclusive OR of * * LS_DATE - %Print file modification date * * LS_SIZE - %Print file size. * * LS_R - Recursive list of subdirectories. * * \param[in] indent Amount of space before file name. Used for recursive * list to indicate subdirectory level. */ //------------------------------------------------------------------------------ void SdBaseFile::ls(Print* pr, uint8_t flags, uint8_t indent) { if (!isDir()) { pr->println(F("bad dir")); return; } rewind(); int8_t status; while ((status = lsPrintNext(pr, flags, indent))) { if (status > 1 && (flags & LS_R)) { uint16_t index = curPosition()/32 - 1; SdBaseFile s; if (s.open(this, index, O_READ)) s.ls(pr, flags, indent + 2); seekSet(32 * (index + 1)); } } } //------------------------------------------------------------------------------ // saves 32 bytes on stack for ls recursion // return 0 - EOF, 1 - normal file, or 2 - directory int8_t SdBaseFile::lsPrintNext(Print *pr, uint8_t flags, uint8_t indent) { dir_t dir; uint8_t w = 0; while (1) { if (read(&dir, sizeof(dir)) != sizeof(dir)) return 0; if (dir.name[0] == DIR_NAME_FREE) return 0; // skip deleted entry and entries for . and .. if (dir.name[0] != DIR_NAME_DELETED && dir.name[0] != '.' && DIR_IS_FILE_OR_SUBDIR(&dir)) break; } // indent for dir level for (uint8_t i = 0; i < indent; i++) pr->write(' '); // print name for (uint8_t i = 0; i < 11; i++) { if (dir.name[i] == ' ')continue; if (i == 8) { pr->write('.'); w++; } pr->write(dir.name[i]); w++; } if (DIR_IS_SUBDIR(&dir)) { pr->write('/'); w++; } if (flags & (LS_DATE | LS_SIZE)) { while (w++ < 14) pr->write(' '); } // print modify date/time if requested if (flags & LS_DATE) { pr->write(' '); printFatDate(pr, dir.lastWriteDate); pr->write(' '); printFatTime(pr, dir.lastWriteTime); } // print size if requested if (!DIR_IS_SUBDIR(&dir) && (flags & LS_SIZE)) { pr->write(' '); pr->print(dir.fileSize); } pr->println(); return DIR_IS_FILE(&dir) ? 1 : 2; } //------------------------------------------------------------------------------ // print uint8_t with width 2 static void print2u(Print* pr, uint8_t v) { if (v < 10) pr->write('0'); pr->print(v, DEC); } //------------------------------------------------------------------------------ /** Print a file's creation date and time * * \param[in] pr Print stream for output. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ bool SdBaseFile::printCreateDateTime(Print* pr) { dir_t dir; if (!dirEntry(&dir)) { DBG_FAIL_MACRO; goto fail; } printFatDate(pr, dir.creationDate); pr->write(' '); printFatTime(pr, dir.creationTime); return true; fail: return false; } //------------------------------------------------------------------------------ /** %Print a directory date field to stdOut. * * Format is yyyy-mm-dd. * * \param[in] fatDate The date field from a directory entry. */ void SdBaseFile::printFatDate(uint16_t fatDate) { printFatDate(SdFat::stdOut(), fatDate); } //------------------------------------------------------------------------------ /** %Print a directory date field. * * Format is yyyy-mm-dd. * * \param[in] pr Print stream for output. * \param[in] fatDate The date field from a directory entry. */ void SdBaseFile::printFatDate(Print* pr, uint16_t fatDate) { pr->print(FAT_YEAR(fatDate)); pr->write('-'); print2u(pr, FAT_MONTH(fatDate)); pr->write('-'); print2u(pr, FAT_DAY(fatDate)); } //------------------------------------------------------------------------------ /** %Print a directory time field to stdOut. * * Format is hh:mm:ss. * * \param[in] fatTime The time field from a directory entry. */ void SdBaseFile::printFatTime(uint16_t fatTime) { printFatTime(SdFat::stdOut(), fatTime); } //------------------------------------------------------------------------------ /** %Print a directory time field. * * Format is hh:mm:ss. * * \param[in] pr Print stream for output. * \param[in] fatTime The time field from a directory entry. */ void SdBaseFile::printFatTime(Print* pr, uint16_t fatTime) { print2u(pr, FAT_HOUR(fatTime)); pr->write(':'); print2u(pr, FAT_MINUTE(fatTime)); pr->write(':'); print2u(pr, FAT_SECOND(fatTime)); } //------------------------------------------------------------------------------ /** Template for SdBaseFile::printField() */ template static int printFieldT(SdBaseFile* file, char sign, Type value, char term) { char buf[3*sizeof(Type) + 3]; char* str = &buf[sizeof(buf)]; if (term) { *--str = term; if (term == '\n') { *--str = '\r'; } } do { Type m = value; value /= 10; *--str = '0' + m - 10*value; } while (value); if (sign) { *--str = sign; } return file->write(str, &buf[sizeof(buf)] - str); } //------------------------------------------------------------------------------ /** Print a number followed by a field terminator. * \param[in] value The number to be printed. * \param[in] term The field terminator. Use '\\n' for CR LF. * \return The number of bytes written or -1 if an error occurs. */ int SdBaseFile::printField(uint16_t value, char term) { return printFieldT(this, 0, value, term); } //------------------------------------------------------------------------------ /** Print a number followed by a field terminator. * \param[in] value The number to be printed. * \param[in] term The field terminator. Use '\\n' for CR LF. * \return The number of bytes written or -1 if an error occurs. */ int SdBaseFile::printField(int16_t value, char term) { char sign = 0; if (value < 0) { sign = '-'; value = -value; } return printFieldT(this, sign, (uint16_t)value, term); } //------------------------------------------------------------------------------ /** Print a number followed by a field terminator. * \param[in] value The number to be printed. * \param[in] term The field terminator. Use '\\n' for CR LF. * \return The number of bytes written or -1 if an error occurs. */ int SdBaseFile::printField(uint32_t value, char term) { return printFieldT(this, 0, value, term); } //------------------------------------------------------------------------------ /** Print a number followed by a field terminator. * \param[in] value The number to be printed. * \param[in] term The field terminator. Use '\\n' for CR LF. * \return The number of bytes written or -1 if an error occurs. */ int SdBaseFile::printField(int32_t value, char term) { char sign = 0; if (value < 0) { sign = '-'; value = -value; } return printFieldT(this, sign, (uint32_t)value, term); } //------------------------------------------------------------------------------ /** Print a file's modify date and time * * \param[in] pr Print stream for output. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ bool SdBaseFile::printModifyDateTime(Print* pr) { dir_t dir; if (!dirEntry(&dir)) { DBG_FAIL_MACRO; goto fail; } printFatDate(pr, dir.lastWriteDate); pr->write(' '); printFatTime(pr, dir.lastWriteTime); return true; fail: return false; } //------------------------------------------------------------------------------ /** Print a file's name * * \param[in] pr Print stream for output. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ size_t SdBaseFile::printName(Print* pr) { char name[13]; if (!getFilename(name)) { DBG_FAIL_MACRO; goto fail; } return pr->print(name); fail: return 0; } //------------------------------------------------------------------------------ /** Print a file's name to stdOut * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ size_t SdBaseFile::printName() { return printName(SdFat::stdOut()); } //------------------------------------------------------------------------------ size_t SdBaseFile::printFileSize(Print* pr) { char buf[10]; char *ptr = fmtDec(fileSize(), buf + sizeof(buf)); while (ptr > buf) *--ptr = ' '; return pr->write(reinterpret_cast(buf), sizeof(buf)); }