Giter Club home page Giter Club logo

inifile's People

Contributors

kaixxx avatar oscarvanl avatar per1234 avatar stevemarple avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

inifile's Issues

ESP8266 compatiblity.

I added minor changes to make library compatible with ESP8266.
strcasecmp(cp, section) not exist in ESP8266 core.

see lines with #ifdef ESP8266 or //TODO:

#include <IniFile.h>
#include <string.h>
#ifdef ESP8266
#include <stdint.h>

#endif

const uint8_t IniFile::maxFilenameLen = INI_FILE_MAX_FILENAME_LEN;

IniFile::IniFile(const char* filename, uint8_t mode,bool caseSensitive)
{
  if (strlen(filename) <= maxFilenameLen)
    strcpy(_filename, filename);
  else
    _filename[0] = '\0';
  _mode = mode;
  _caseSensitive = caseSensitive;
}

IniFile::~IniFile()
{
  //if (_file)
  //  _file.close();
}


bool IniFile::validate(char* buffer, size_t len) const
{
  uint32_t pos = 0;
  error_t err;
  while ((err = readLine(_file, buffer, len, pos)) == errorNoError)
    ;
  if (err == errorEndOfFile) {
    _error = errorNoError;
    return true;
  }
  else {
    _error = err;
    return false;
  }
}

bool IniFile::getValue(const char* section, const char* key,
              char* buffer, size_t len, IniFileState &state) const
{
  bool done = false;
  if (!_file) {
    _error = errorFileNotOpen;
    return true;
  }

  switch (state.getValueState) {
  case IniFileState::funcUnset:
    state.getValueState = (section == NULL ? IniFileState::funcFindKey
               : IniFileState::funcFindSection);
    state.readLinePosition = 0;
    break;

  case IniFileState::funcFindSection:
    if (findSection(section, buffer, len, state)) {
      if (_error != errorNoError)
    return true;
      state.getValueState = IniFileState::funcFindKey;
    }
    break;

  case IniFileState::funcFindKey:
    char *cp;
    if (findKey(section, key, buffer, len, &cp, state)) {
      if (_error != errorNoError)
    return true;
      // Found key line in correct section
      cp = skipWhiteSpace(cp);
      removeTrailingWhiteSpace(cp);

      // Copy from cp to buffer, but the strings overlap so strcpy is out
      while (*cp != '\0')
    *buffer++ = *cp++;
      *buffer = '\0';
      return true;
    }
    break;

  default:
    // How did this happen?
    _error = errorUnknownError;
    done = true;
    break;
  }

  return done;
}

bool IniFile::getValue(const char* section, const char* key,
              char* buffer, size_t len) const
{
  IniFileState state;
  while (!getValue(section, key, buffer, len, state))
    ;
  return _error == errorNoError;
}


bool IniFile::getValue(const char* section, const char* key,
             char* buffer, size_t len, char *value, size_t vlen) const
{
  if (getValue(section, key, buffer, len) < 0)
    return false; // error
  if (strlen(buffer) >= vlen)
    return false;
  strcpy(value, buffer);
  return true;
}


// For true accept: true, yes, 1
 // For false accept: false, no, 0
bool IniFile::getValue(const char* section, const char* key, 
              char* buffer, size_t len, bool& val) const
{
  if (getValue(section, key, buffer, len) < 0)
    return false; // error

  if (strcmp(buffer, "true") == 0 || //TODO:strcasecom ?
      strcmp(buffer, "yes") == 0 ||
      strcmp(buffer, "1") == 0) {
    val = true;
    return true;
  }
  if (strcmp(buffer, "false") == 0 || //TODO:strcasecom ?
      strcmp(buffer, "no") == 0 ||
      strcmp(buffer, "0") == 0) {
    val = false;
    return true;
  }
  return false; // does not match any known strings      
}

bool IniFile::getValue(const char* section, const char* key,
              char* buffer, size_t len, int& val) const
{
  if (getValue(section, key, buffer, len) < 0)
    return false; // error

  val = atoi(buffer);
  return true;
}

bool IniFile::getValue(const char* section, const char* key,    \
              char* buffer, size_t len, uint16_t& val) const
{
  long longval;
  bool r = getValue(section, key, buffer, len, longval);
  if (r)
    val = uint16_t(longval);
  return r;
}

bool IniFile::getValue(const char* section, const char* key,
              char* buffer, size_t len, long& val) const
{
  if (getValue(section, key, buffer, len) < 0)
    return false; // error

  val = atol(buffer);
  return true;
}

bool IniFile::getValue(const char* section, const char* key,
              char* buffer, size_t len, unsigned long& val) const
{
  if (getValue(section, key, buffer, len) < 0)
    return false; // error

  char *endptr;
  unsigned long tmp = strtoul(buffer, &endptr, 10);
  if (endptr == buffer)
    return false; // no conversion
  if (*endptr == '\0') {
    val = tmp;
    return true; // valid conversion
  }
  // buffer has trailing non-numeric characters, and since the buffer
  // already had whitespace removed discard the entire results
  return false; 
}


bool IniFile::getValue(const char* section, const char* key,
              char* buffer, size_t len, float & val) const
{
  if (getValue(section, key, buffer, len) < 0)
    return false; // error

  char *endptr;
  float tmp = strtod(buffer, &endptr);
  if (endptr == buffer)
    return false; // no conversion
  if (*endptr == '\0') {
    val = tmp;
    return true; // valid conversion
  }
  // buffer has trailing non-numeric characters, and since the buffer
  // already had whitespace removed discard the entire results
  return false; 
}


bool IniFile::getIPAddress(const char* section, const char* key,
                  char* buffer, size_t len, uint8_t* ip) const
{
  // Need 16 chars minimum: 4 * 3 digits, 3 dots and a null character
  if (len < 16)
    return false;

  if (getValue(section, key, buffer, len) < 0) 
    return false; // error

  int i = 0;
  char* cp = buffer;
  ip[0] = ip[1] = ip[2] = ip[3] = 0;
  while (*cp != '\0' && i < 4) {
    if (*cp == '.') {
      ++i;
      ++cp;
      continue;
    }
    if (isdigit(*cp)) {
      ip[i] *= 10;
      ip[i] += (*cp - '0');
    }
    else {
      ip[0] = ip[1] = ip[2] = ip[3] = 0;
      return false;
    }
    ++cp;
  }
  return true;
}


#if defined(ARDUINO) && ARDUINO >= 100
bool IniFile::getIPAddress(const char* section, const char* key,
                  char* buffer, size_t len, IPAddress& ip) const
{
  // Need 16 chars minimum: 4 * 3 digits, 3 dots and a null character
  if (len < 16)
    return false;

  if (getValue(section, key, buffer, len) < 0) 
    return false; // error

  int i = 0;
  char* cp = buffer;
  ip = IPAddress(0, 0, 0, 0);
  while (*cp != '\0' && i < 4) {
    if (*cp == '.') {
      ++i;
      ++cp;
      continue;
    }
    if (isdigit(*cp)) {
      ip[i] *= 10;
      ip[i] += (*cp - '0');
    }
    else {
      ip = IPAddress(0, 0, 0, 0);
      return false;
    }
    ++cp;
  }
  return true;
}
#endif

bool IniFile::getMACAddress(const char* section, const char* key,
                   char* buffer, size_t len, uint8_t mac[6]) const
{
  // Need 18 chars: 6 * 2 hex digits, 5 : or - and a null char
  if (len < 18)
    return false;

  if (getValue(section, key, buffer, len) < 0)
    return false; // error

  int i = 0;
  char* cp = buffer;
  memset(mac, 0, 6);

  while (*cp != '\0' && i < 6) {
    if (*cp == ':' || *cp == '-') {
      ++i;
      ++cp;
      continue;
    }
    if (isdigit(*cp)) {
      mac[i] *= 16; // working in hex!
      mac[i] += (*cp - '0');
    }
    else {
      if (isxdigit(*cp)) {
    mac[i] *= 16; // working in hex!
    mac[i] += (toupper(*cp) - 55); // convert A to 0xA, F to 0xF
      }
      else {
    memset(mac, 0, sizeof(mac));
    return false;
      }
    }
    ++cp;
  }
  return true;
}

//int8_t IniFile::readLine(File &file, char *buffer, size_t len, uint32_t &pos)
IniFile::error_t IniFile::readLine(File &file, char *buffer, size_t len, uint32_t &pos)
{
  if (!file)
    return errorFileNotOpen;

  if (len < 3) 
    return errorBufferTooSmall;

#ifndef ESP8266
  if (!file.seek(pos))
     return errorSeekError;
  size_t bytesRead = file.read(buffer, len);
#endif
#ifdef ESP8266
  if (!file.seek(pos,SeekSet))
       return errorSeekError;
  size_t bytesRead = file.read((uint8_t *)buffer, len);
#endif




  if (!bytesRead) {
    buffer[0] = '\0';
    //return 1; // done
    return errorEndOfFile;
  }

  for (size_t i = 0; i < bytesRead && i < len-1; ++i) {
    // Test for '\n' with optional '\r' too
    // if (endOfLineTest(buffer, len, i, '\n', '\r')

    if (buffer[i] == '\n' || buffer[i] == '\r') {
      char match = buffer[i];
      char otherNewline = (match == '\n' ? '\r' : '\n'); 
      // end of line, discard any trailing character of the other sort
      // of newline
      buffer[i] = '\0';

      if (buffer[i+1] == otherNewline)
    ++i;
      pos += (i + 1); // skip past newline(s)
      //return (i+1 == bytesRead && !file.available());
      return errorNoError;
    }
  }
  if (!file.available()) {
    // end of file without a newline
    buffer[bytesRead] = '\0';
    // return 1; //done
    return errorEndOfFile;
  }

  buffer[len-1] = '\0'; // terminate the string
  return errorBufferTooSmall;
}

bool IniFile::isCommentChar(char c)
{
  return (c == ';' || c == '#');
}

char* IniFile::skipWhiteSpace(char* str)
{
  char *cp = str;
  while (isspace(*cp))
    ++cp;
  return cp;
}

void IniFile::removeTrailingWhiteSpace(char* str)
{
  char *cp = str + strlen(str) - 1;
  while (cp >= str && isspace(*cp))
    *cp-- = '\0';
}

bool IniFile::findSection(const char* section, char* buffer, size_t len, 
                 IniFileState &state) const
{
  if (section == NULL) {
    _error = errorSectionNotFound;
    return true;
  }

  error_t err = IniFile::readLine(_file, buffer, len, state.readLinePosition);

  if (err != errorNoError && err != errorEndOfFile) {
    // Signal to caller to stop looking and any error value
    _error = err;
    return true;
  }

  char *cp = skipWhiteSpace(buffer);
  //if (isCommentChar(*cp))
  //return (done ? errorSectionNotFound : 0);
  if (isCommentChar(*cp)) {
    // return (err == errorEndOfFile ? errorSectionNotFound : errorNoError);
    if (err == errorSectionNotFound) {
      _error = err;
      return true;
    }
    else
      return false; // Continue searching
  }

  if (*cp == '[') {
    // Start of section
    ++cp;
    cp = skipWhiteSpace(cp);
    char *ep = strchr(cp, ']');
    if (ep != NULL) {
      *ep = '\0'; // make ] be end of string
      removeTrailingWhiteSpace(cp);
      if (_caseSensitive) {
    if (strcmp(cp, section) == 0) {
      _error = errorNoError;
      return true;
    }
      }
      else {
    if (strcmp(cp, section) == 0) { //TODO:strcmp
      _error = errorNoError;
      return true;
    }
      }
    }
  }

  // Not a valid section line
  //return (done ? errorSectionNotFound : 0);
  if (err == errorEndOfFile) {
    _error = errorSectionNotFound;
    return true;
  }

  return false;
}

// From the current file location look for the matching key. If
// section is non-NULL don't look in the next section
bool IniFile::findKey(const char* section, const char* key,
             char* buffer, size_t len, char** keyptr,
             IniFileState &state) const
{
  if (key == NULL || *key == '\0') {
    _error = errorKeyNotFound;
    return true;
  }

  error_t err = IniFile::readLine(_file, buffer, len, state.readLinePosition);
  if (err != errorNoError && err != errorEndOfFile) {
    _error = err;
    return true;
  }

  char *cp = skipWhiteSpace(buffer);
  // if (isCommentChar(*cp))
  //   return (done ? errorKeyNotFound : 0);
  if (isCommentChar(*cp)) {
    if (err == errorEndOfFile) {
      _error = errorKeyNotFound;
      return true;
    }
    else
      return false; // Continue searching
  }

  if (section && *cp == '[') {
    // Start of a new section
    _error = errorKeyNotFound;
    return true;
  }

  // Find '='
  char *ep = strchr(cp, '=');
  if (ep != NULL) {
    *ep = '\0'; // make = be the end of string
    removeTrailingWhiteSpace(cp);
    if (_caseSensitive) {
      if (strcmp(cp, key) == 0) {
    *keyptr = ep + 1;
    _error = errorNoError;
    return true;
      }
    }
    else {
      if (strcmp(cp, key) == 0) { //TODO:strcasecmp
    *keyptr = ep + 1;
    _error = errorNoError;
    return true;
      }
    }
  }

  // Not the valid key line
  if (err == errorEndOfFile) {
    _error = errorKeyNotFound;
    return true;
  }
  return false;
}

bool IniFile::getCaseSensitive(void) const
{
  return _caseSensitive;
}

void IniFile::setCaseSensitive(bool cs)
{
  _caseSensitive = cs;
}

IniFileState::IniFileState()
{
  readLinePosition = 0;
  getValueState = funcUnset;
}

update value

Hi,
i will like know if is possible update the value on file .ini

Thanks

Conflic Ethernet2.h

Hi Steve,

i have a new Ethernet2 Board i want to use, but this works only with the Ethernet2.h lib, but IniFile ist requier Ethernet.h, do you have an idea to solve this?

kind reguards michael

Slight modification to handle SD_MMC connections

Hi,

Great lib, thank you!

I'm using SD_MMC instead of SD/SPI, and in order to get this lib to work, I had to change two lines:

Line 10: #include <SD_MMC.h>
Line 158: _file = SD_MMC.open(_filename, _mode);

And then the repository works perfectly with SD_MMC connections.

parse missing key error occur

A.ini
[A]
a=1
[B]
b=1

then we getValue("A","b",buffer,len) == true

in src/IniFile.cpp line 140: if (getValue(section, key, buffer, len) < 0) need changed to: if (getValue(section, key, buffer, len) == false),because line 92: bool IniFile::getValue(const char* section, const char* key,...) returns bool,but not int.same as in line 160,170,190,214,248

Add cross platform features

Hi Steve, are you still maintaining and/or updating this library - I see no commits for 6 months?

After doing some searching, your library seems like exactly what I'm looking for - surprised that there are no contributors - thoughts? Better solution elsewhere?

I'm a newbie to arduino (and haven't coded for 25 years), so still on the learning curve (and what I remember of C coding is rusty.....

Wondering if its worth extending your library to handle different platforms? I think the logic of the library seems sound though in the first instance I'd like to pass a file pointer to the constructor that is generic (arduino SD File (regardless of SD library used) or linux gcc FILE) rather than a filename.

Would this be something easy to implement?

Many thanks,
Brendan

Ini file /net.ini does not exist

Hi, I installed the iniFile library 1.0.3 from library manager but the IniFile Example Sketch doesn't find the filo on the SD card.
I tested the SD with the sd/listfiles example and it works fine.

Any suggestion is appreciated.

Yhanks

Ignoring/truncating lines that are too long?

Hello,

If I change line 423 in IniFile.cpp from:

return errorBufferTooSmall;
to
return errorNoError;

Would that result in the validate function not returning an error but instead just truncating lines that are too long (instead of returning an invalid file error)?

What's your reasoning behind invalidating the entire file if any lines are longer than the buffer length instead of just silently (or not silently) truncating them?

My thinking is if an end-user inadvertently has one line go over inibufferlen, the entire file is rejected, instead of just the offending line(s).

Thank you.

Can you provide example to use IniFile with SdFat?

It seems that it is possible to use SdFat (with teensy 4.1)
But defining PREFER_SDFAT_LIBRARY seems not to work because of type of File
Can you provide a simple example please?

thanks

Here the code I use, no instantiation for the moment, just #include <IniFile.h>

#include <SPI.h>
#define PREFER_SDFAT_LIBRARY
#include <IPAddress.h>
#include <IniFile.h>

#define SD_FAT_TYPE 3

// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else  // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif  // SDCARD_SS_PIN

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else  // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif  // HAS_SDIO_CLASS

#if SD_FAT_TYPE == 0
SdFat sd;
File file;
File configFile;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
File32 configFile;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
ExFile configFile;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
FsFile configFile;
#else  // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif  // SD_FAT_TYPE

void setup() {
  Serial.begin(112500);
  while (!Serial) {}

  Serial.println(F("\nType any character to begin."));
  while (!Serial.available()) {
    yield();
  }
  Serial.print("Initializing SD card...");

  if (!SD.begin(SD_CONFIG)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

  // open the file.
  file = SD.open("test.txt", FILE_WRITE);

  // if the file opened okay, write to it:
  if (file) {
    Serial.print("Writing to test.txt...");
    file.println("testing 1, 2, 3.");
    // close the file:
    file.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }

  // re-open the file for reading:
  file = SD.open("test.txt");
  if (file) {
    Serial.println("test.txt:");

    // read from the file until there's nothing else in it:
    while (file.available()) {
      Serial.write(file.read());
    }
    // close the file:
    file.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
}
void loop() {
  // nothing happens after setup
}

Feature request w/ source

The current library version does not support comments at the end of a line containing ini information.
FOO = FooInfo # default value <= this causes problems
A minor change to IniFile::removeTrailingWhiteSpace() will allow for that.

void IniFile::removeTrailingWhiteSpace(char* str)
{
if (str == nullptr)
return;
char *cp;
if ((cp = strchr(str, '#')) || (cp = strchr(str, ';'))) // check for comment characters here
*cp = '\0'; // if found, shorten the string
cp = str + strlen(str) - 1;
while (cp >= str && isspace(*cp))
*cp-- = '\0';
}
This does exclude the comment characters from being within the ini information.
If you have comments or wish to discuss this further my email address is:
[email protected]

buffer size optimization idea

Hi, just a thought in regards to:

The user-supplied buffer must be large enough
to accomodate the longest line in the file.

This can be optimized a bit in the readLine scanner. If it detects that a line is a comment, it can scan ahead until the next new line, incrementing pos, but not being bound by the current buffer length limitation. By ignoring comment line length, you can trim allot off of your buffer sizes to only the longest variable line now.

I just did a quick hack to make it so, but it saves allot of memory and allows you to include verbose comments without having to be careful.

IniFile::error_t IniFile::readUntilNewLine(File &file, char *buffer, size_t len, uint32_t &pos){

    char *b=buffer;
    while(1){
          size_t bytesRead = file.read(b, len);
          if (!bytesRead) {
            buffer[0] = '\0';
            return errorEndOfFile;
          }

          for (size_t i = 0; i < bytesRead && i < len-1; ++i) {
            // Test for '\n' with optional '\r' too
            // if (endOfLineTest(buffer, len, i, '\n', '\r')

            if (buffer[i] == '\n' || buffer[i] == '\r') {
              char match = buffer[i];
              char otherNewline = (match == '\n' ? '\r' : '\n'); 
              // end of line, discard any trailing character of the other sort
              // of newline
              buffer[i] = '\0';

              if (buffer[i+1] == otherNewline)
            ++i;
              pos += (i + 1); // skip past newline(s)
              //return (i+1 == bytesRead && !file.available());
              return errorNoError;
            }
          }
          if (!file.available()) {
            // end of file without a newline
            buffer[bytesRead] = '\0';
            // return 1; //done
            return errorEndOfFile;
          }
          *b+=len;
    }

}


IniFile::error_t IniFile::readLine(File &file, char *buffer, size_t len, uint32_t &pos)
{
...
//does not account for whitespace before comment char lazy..
if (isCommentChar(buffer[0]))return readUntilNewLine(file, buffer,len, pos);

A save Option would be great

Hello
nice Project I just wonder why there is no save Option,
I try to handle this but it's a pain in the ass.

Support Double variables types for getValue

I find it useful that getValue allows for a fifth argument for the variable to store the read value into, however, noticed it lacked the support for 'double' types. Would it be possible to add this, or is there an intentional decision for omitting this type?

Not an issue, more a question

So i have to say, your solution for reading files off of a SD card is considerably more streamlined then other solutions i have seen out there. But i do have a question/request. Im building a reverse geocache platform and i want to use your library so that i can put gps coordinates onto my sd card and not have to re flash my arduino every time i want to change the route. Currently im using a hard coded array with floating locations. IE:
float latArray[] = {11.111111, 22.222222, 33.333333};
float longArray[] = {-11.111111, -22.222222, -33.333333};
since your codes is written to return char, i am not able to make it work with my code. I was hoping you would have a suggestion as to the easiest way to use what you have written so that i can use it in my code. Thanks for any info you can provide.

Delete contents

Very weird problem. I added setings in the data file. Upload the code but reads nothing from the file. Open file on PC and the content is missing. Some how the data gets deleted.

Issue with larger ini file and duplicate keys?

Hi,
Working on a fairly simple ini file but size or the keys may be the issue?

The ini file contents:
[main] scheduler = 0 auto = 0 temperature_set = 30 override = 0 [0] 0 = 1 1 = 1 2 = 1 3 = 1 4 = 1 5 = 1 6 = 1 7 = 1 8 = 1 9 = 1 10 = 1 11 = 1 12 = 1 13 = 1 14 = 1 15 = 1 16 = 1 17 = 1 18 = 1 19 = 1 20 = 1 21 = 1 22 = 1 23 = 1 [1] 0 = 1 1 = 1 2 = 1 3 = 1 4 = 1 5 = 1 6 = 1 7 = 1 8 = 1 9 = 1 10 = 1 11 = 1 12 = 1 13 = 1 14 = 1 15 = 1 16 = 1 17 = 1 18 = 1 19 = 1 20 = 1 21 = 1 22 = 1 23 = 1 [2] 0 = 1 1 = 1 2 = 1 3 = 1 4 = 1 5 = 1 6 = 1 7 = 1 8 = 1 9 = 1 10 = 1 11 = 1 12 = 1 13 = 1 14 = 1 15 = 1 16 = 1 17 = 1 18 = 1 19 = 1 20 = 1 21 = 1 22 = 1 23 = 1 [3] 0 = 1 1 = 1 2 = 1 3 = 1 4 = 1 5 = 1 6 = 1 7 = 1 8 = 1 9 = 1 10 = 1 11 = 1 12 = 1 13 = 1 14 = 1 15 = 1 16 = 1 17 = 1 18 = 1 19 = 1 20 = 1 21 = 1 22 = 1 23 = 1 [4] 0 = 1 1 = 1 2 = 1 3 = 1 4 = 1 5 = 1 6 = 1 7 = 1 8 = 1 9 = 1 10 = 1 11 = 1 12 = 1 13 = 1 14 = 1 15 = 1 16 = 1 17 = 1 18 = 1 19 = 1 20 = 1 21 = 1 22 = 1 23 = 1 [5] 0 = 1 1 = 1 2 = 1 3 = 1 4 = 1 5 = 1 6 = 1 7 = 1 8 = 1 9 = 1 10 = 1 11 = 1 12 = 1 13 = 1 14 = 1 15 = 1 16 = 1 17 = 1 18 = 1 19 = 1 20 = 1 21 = 1 22 = 1 23 = 1 [6] 0 = 1 1 = 1 2 = 1 3 = 1 4 = 1 5 = 1 6 = 1 7 = 1 8 = 1 9 = 1 10 = 1 11 = 1 12 = 1 13 = 1 14 = 1 15 = 1 16 = 1 17 = 1 18 = 1 19 = 1 20 = 1 21 = 1 22 = 1 23 = 1

And the code I'm using to retrieve it:
(DEBUG_PRINT is an alias to Serial.println)

`
const size_t ini_bufferLen = 1000;
char ini_buffer[ini_bufferLen];
const char *ini_filename = "/test.ini";
IniFile ini(ini_filename);

if (!ini.open()) {
DEBUG_PRINT("PANIC - we are in read_inifiledata() and expected the file to exist BUT IT DOES NOT");
} else {
// read ini file and check for valid
if (!ini.validate(ini_buffer, ini_bufferLen)) {
DEBUG_PRINT("PANIC - the ini file did not validate, so we are rejecting it");
DEBUG_PRINT(String(ini.getError()));
} else {
// valid ini file so grab values
int tmp_day=0;
int tmp_hour=0;
while(tmp_day < 7) {
tmp_hour=0;
while (tmp_hour< 24) {
char daybuf[4],hourbuf[4];
itoa(tmp_day, daybuf, 6);
itoa(tmp_hour, hourbuf, 6);
if (ini.getValue(daybuf, hourbuf, ini_buffer, ini_bufferLen)) {
DEBUG_PRINT("Loaded day " + String(tmp_day) + " hour " + String(tmp_hour) + " Value: " + String(ini_buffer));
} else {
DEBUG_PRINT("Ini section NOT found - day " + String(tmp_day) + " and hour " + String(tmp_hour));
};
DEBUG_PRINT("ini error: " + String(ini.getError()));
tmp_hour++;
};
tmp_day++;
};
};
`

It works for the first few iterations, but by the time it gets to day 0, hour 16 it fails and will fail the rest of that day:
16:57:07.867 -> Ini section NOT found - day 0 and hour 16
16:57:07.867 -> ini error: 6
16:57:07.867 -> Ini section NOT found - day 0 and hour 17
16:57:07.867 -> ini error: 6
(and so on)
It then moves to the next day and works:
6:57:08.103 -> Loaded day 1 hour 0 Value: 1
16:57:08.103 -> ini error: 0
16:57:08.103 -> Loaded day 1 hour 1 Value: 1
16:57:08.103 -> ini error: 0
16:57:08.103 -> Loaded day 1 hour 2 Value: 1
(etc, until it gets to hour 16 and fails again):
16:57:08.337 -> Loaded day 1 hour 15 Value: 1
16:57:08.337 -> ini error: 0
16:57:08.337 -> Ini section NOT found - day 1 and hour 16
16:57:08.337 -> ini error: 6
16:57:08.337 -> Ini section NOT found - day 1 and hour 17
16:57:08.337 -> ini error: 6

It continues like that until it gets to day 15, again 16th value fails, it then fails the next day section, and fails all future sections.

16:57:11.624 -> Loaded day 5 hour 15 Value: 1
16:57:11.624 -> ini error: 0
16:57:11.857 -> Ini section NOT found - day 5 and hour 16
16:57:11.857 -> ini error: 6
16:57:11.857 -> Ini section NOT found - day 5 and hour 17
16:57:11.857 -> ini error: 6
16:57:11.857 -> Ini section NOT found - day 5 and hour 18
16:57:11.857 -> ini error: 6
16:57:11.857 -> Ini section NOT found - day 5 and hour 19
16:57:11.857 -> ini error: 6
16:57:11.857 -> Ini section NOT found - day 5 and hour 20
16:57:11.857 -> ini error: 6
16:57:11.857 -> Ini section NOT found - day 5 and hour 21
16:57:11.857 -> ini error: 6
16:57:12.093 -> Ini section NOT found - day 5 and hour 22
16:57:12.093 -> ini error: 6
16:57:12.093 -> Ini section NOT found - day 5 and hour 23
16:57:12.093 -> ini error: 6
16:57:12.093 -> Ini section NOT found - day 6 and hour 0
16:57:12.093 -> ini error: 5
16:57:12.093 -> Ini section NOT found - day 6 and hour 1
16:57:12.093 -> ini error: 5
16:57:12.093 -> Ini section NOT found - day 6 and hour 2
16:57:12.093 -> ini error: 5
16:57:12.093 -> Ini section NOT found - day 6 and hour 3
16:57:12.093 -> ini error: 5

I've checked the ini file is valid, i'm not getting any memory issues or any other error messages, it just appears the iniFile library stops at each of these. It feels like a buffer issue, but I've given it huge buffers to see if that helps and no luck.

Real Time Clock Conflict

First of all, thank you for writing such a useful lib. It's really coming in handy for my remote field station. However, I am having one issue. I've chased down a conflict, it seems, with my RTC from spark fun. If I initialize the clock (RTC.configure(3,4,5,6), for example), the ini.open() returns false. It doesn't matter where I configure the RTC (before or after). Do you have any tips as to where I may look in resolving this?

Thanks again for your work.

Jeremy

[Feature request] create set-functions

Hi,
first of all: I like your project very much and I will definitely use it.

I think it would be great to write back some ini values, so one would be able to write changed values to a certain section to the ini file, or even create new entries.

I usually would store settings in the eeprom but as I saw your library I thought it would be great to have all the settings in a single file so one could transfer them to a new Arduino and user-selections will be stored on the SD-Card.

Do you plan to have that feature in yout lib?

Best regards!

Thanks for iniFile library

Hello,
Been looking to find help to read data off of SD Card for my clock project and this will help a lot. Making a clock that will get data off of the internet and scroll it on the screen and display the time. I also want it to display reminders for different medicines I take. I'm using the 16x24 LED matrix from Adafruit. I've seen you made your own Arduino compatible, that's pretty cool. So far I hadn't had memory problems with my Uno, but I might need to move up to bigger chip later. Well have a good day.

Not working when using SdFat instead of SD library

Hi!

Thanks for your work on this library!

I've been trying to use IniFile compining against SdFat instead the defaukt SD library. I've used the examples included in IniFile witout success.

  • Example "IniBrowseExample", without any modifications (compiling using SD.h library) is successful:

`#include <SD.h>

#include <SPI.h>
#include <IPAddress.h>
#include <IniFile.h>

// The select pin used for the SD card
[...]`

  • Example "IniBrowseExample" compiling using SdFat is not successful:
    `#define PREFER_SDFAT_LIBRARY 1

#include <SdFat.h>

#include <SPI.h>
#include <IPAddress.h>
#include <IniFile.h>

// The select pin used for the SD card
[...]`

Error:

tmp/arduino/sketches/BB2A6256ECD89697A9217989C990A171/sketch/IniBrowseExample.ino.cpp.o: In function IniFile::open()':
/home/user/Arduino/libraries/IniFile/src/IniFile.h:161: undefined reference to SD' /tmp/arduino/sketches/BB2A6256ECD89697A9217989C990A171/sketch/IniBrowseExample.ino.cpp.o: In function setup':
/tmp/.arduinoIDE-unsaved202339-2452-1rlkvoh.nh7h/IniBrowseExample/IniBrowseExample.ino:72: undefined reference to IniFile::IniFile(char const*, int, bool)' /tmp/.arduinoIDE-unsaved202339-2452-1rlkvoh.nh7h/IniBrowseExample/IniBrowseExample.ino:126: undefined reference to SD'
/tmp/.arduinoIDE-unsaved202339-2452-1rlkvoh.nh7h/IniBrowseExample/IniBrowseExample.ino:126: undefined reference to `SD'
collect2: error: ld returned 1 exit status

exit status 1

Compilation error: exit status 1`

  • Example "IniBrowseExample" compiling using SdFat with some extra options is neither successful:

`#define PREFER_SDFAT_LIBRARY 1

#include <SdFat.h>
SdFat SD;

#include <SPI.h>
#include <IPAddress.h>
#include <IniFile.h>

// The select pin used for the SD card
[...]`

Error:

/tmp/arduino/sketches/BB2A6256ECD89697A9217989C990A171/sketch/IniBrowseExample.ino.cpp.o: In function setup':
/tmp/.arduinoIDE-unsaved202339-2452-1rlkvoh.nh7h/IniBrowseExample/IniBrowseExample.ino:73: undefined reference to `IniFile::IniFile(char const*, int, bool)'
collect2: error: ld returned 1 exit status

exit status 1

Compilation error: exit status 1`

Is there any way to solve this? If I can help any way please let me know.

Thanks!

Building on ESP8266 via PlatformIO resulted in error

I installed iniFile via PlatformIO (V1.3) for my ESP8266 project. Building resulted in the following error at line 389:

error invalid conversion from char to uint8 t aka unsigned char

line 389 = size_t bytesRead = file.read(buffer, len);

but adding an OR that included the ESP8266 define at line 386 seems to have fixed it.

line 386 = #if (defined(ARDUINO_ARCH_ESP32) || defined(ESP8266)) && !defined(PREFER_SDFAT_LIBRARY)

c++11 required

Hi Steve,
I have been trying to make the test but I got a failure:

IniFile.cpp:44:2: warning: identifier ‘nullptr’ is a keyword in C++11 [-Wc++0x-compat]
  char *cp = nullptr;

This is my configuration:

>>> g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.5.0-12ubuntu1~16.04' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 5.5.0 20171010 (Ubuntu 5.5.0-12ubuntu1~16.04)

Then in Makefile, I add the flag c++11.

CXXFLAGS += -ggdb -Wall -I. -std=c++11

It has fixed the issue. I just wanted to notice into consideration that maybe my configuration is not up-to-date.


Raphael.

use same code Spifs and with SD

Steve,
Great tool and thank you for your contribution to the community!

Are you aware of anyone making this code capable of reading both spifs and SD files. That is, I want to use one set of code to alternately read either an ini file from SD or one from Spiffs. (My goal is to use the SD for updates of the ini but keep the current active ini and the "factory reset" ini in spifs (or EEPROM. )

Thanks again.
Pete

Inline comments

Hi, I noticed inline comments are not permitted.

This doesn't work:

testFrequency=60 # How frequently the test should be conducted, in seconds

Whereas this does:

# How frequently the test should be conducted, in seconds
testFrequency=60 

I'd love to be able to use the former as I think it looks neater.

improvements

I read that you no longer want to work on this library.
But the same I tell you my idea.

It would be very nice as well.

IniFile ini("config.ini", Buffer, BufferLenght);

and

ini.getValue("enableMailOff", enableMailOff);

instead of

ini.getValue(NULL, "enableMailOff", buffer, len, enableMailOff);

Unable to read the data inside a file

Hii,

I want to read the maximum profiles and order in which it is stored, for that, I am storing the data in a pointer array from buffer. When I am using the pointer array outside the loop it show me nothing as if data has been not stored ? I can see the data in buffer using Serial monitor and also using pointer array. I can see the data but only in a loop and if I print outside the loop It doesn't print anything. It will be more clear when I will provide the code.
char *SP[80];
void setup() {
// debug output at 9600 baud
Serial.begin(9600);

pinMode(10,OUTPUT);
// setup SD-card
Serial.print(F("Initializing SD card..."));
if (!SD.begin(10)) {
Serial.println(F(" failed!"));
while (true);
}

Serial.println(F(" done."));

//INI FILE
const char *filename = "/config3.ini";
const size_t bufferLen = 80;
char buffer[bufferLen];
IniFile ini(filename);
if (!ini.open()) {
Serial.print("Ini file ");
Serial.print(filename);
Serial.println(" does not exist");
//error("Ini Setting File Does NOt Exist");
}
Serial.println("Ini file exists");

// Check the file is valid. This can be used to warn if any lines
// are longer than the buffer.
if (!ini.validate(buffer, bufferLen)) {
Serial.print("ini file ");
Serial.print(ini.getFilename());
Serial.print(" not valid: ");
//error("Setting File Is Not Valid");
}
// to Determine the number of profiles and it's order
do {

j = j + 1;  // int 1

itoa(j, number, 10); // number to String 1

if( ini.getValue("PROFILES", number , buffer, bufferLen)){

SP[j]= buffer;
Serial.println(SP[j]);

count = j;

} else{
  
  buffer[0] = '\0';

}

} while(buffer[0] != '\0' );

Serial.print("MAXIMUM SOUND PROFILES:");

Serial.println(count);
ini.close();

for(int i = 0; i <= count; i++){

Serial.println(SP[i]);

}
}`

INI file not found

Hi,

I've tried your library but it doesn't find the file on SD card. When using the SD library I successfully manage to read the file.

I'm using Arduino Duemilanove with Ethernet Shild W5100 and Arduino environment 1.0.1.

What am I doing wrong?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.