Modifica codice con String in codice con char[]...

Salve,
vorrei modificare delle funzioni su uno sketch che fanno uso della classe String per farle funzionare con gli array char, ma sto avendo difficoltà… Sono parecchio arrugginito con il C ed i puntatori e malgrado le diverse ore passate davanti allo schermo a leggere esempi e provare a scrivere codice, non ne vengo a capo. Il codice da modificare è questo:

String inString = String((char*)"");

void ServeWebClients()
{
    EthernetClient client = server.available(); // Wired
    if (client) 
    {
        inString = client.readStringUntil('\n');
        client << F("HTTP/1.1 200 OK") << endl;
        client << F("Content-Type: text/html") << endl;
        client << F("Connection: close") << endl << endl;
        #if defined(USE_REM_DISPLAY)
          if (Command((char*)"disp")) SendToremDisplay(sensors); // Send data to remote dispplay
        #endif
        if (Command((char*)"save")) SaveValues();
        if (Command((char*)"reset")) ResetValues();
        if (Command((char*)"restart")) while(1); // stay here until the watchdog barks
        if (Command((char*)"ntp")) UpdateTime(); // reload the ntp time
        if (Command((char*)"resetwdc")) eeprom_write_byte ((uint8_t*)EE_CTR, (byte*)0);
        if (Command((char*)"resetday")) eeprom_write_byte ((uint8_t*)EE_RESETDAY, (byte*)day());
        int i=inString.indexOf("?");
        if(i != -1) ReadValue(i);
        ShowStatus(client);
        client.stop();
    }
}

bool Command(char* command)
{
  int i = inString.indexOf(command);
  if (i == -1) return false;
  return true;
}

void ReadValue(int i)
{
    // String format is "?0=12345"
    //                  "?3=-12345"
    //                  "?G=12345"
    long val = 0;
    bool neg = false;
    int j = i + 3;
    int address = inString[i+1];
    if((address >= '0' && address < '9') || (address >= 'A' && address < 'J')) 
    {
        char c = inString[j];
        if(c == '-')
        {
            neg = true;
            j ++;
            c = inString[j];
        }
        while(c >= '0' && c <= '9')
        {
            val = 10 * val + (c - '0');
            j ++;
            c = inString[j];
        }
        if(neg) val = -val;
        if(address >= 'A') // Address = 'A...'J' to write the total counters
        {
            sensors[address-'A']->NewTotal(val);
        }
        else // Address = '0'...'9' to write the day counters
        {
            // Let the sensor write the value to eeprom
            sensors[address-'0']->Update(val);
        }
    }
}

E quello che ho scritto fino ad ora è questo (ho lasciato le righe commentate del vecchio codice per riferimento):

//String inString = String((char*)"");
char inString[81];

void ServeWebClients()
{
    EthernetClient client = server.available(); // Wired
    if (client) 
    {
//        inString = client.readStringUntil('\n');
        size_t numchars = client.readBytes(inString, 80); 
        inString[numchars] = '\0'; // terminate the string

        client << F("HTTP/1.1 200 OK") << endl;
        client << F("Content-Type: text/html") << endl;
        client << F("Connection: close") << endl << endl;
        #if defined(USE_REM_DISPLAY)
          if (Command((char*)"disp")) SendToremDisplay(sensors); // Send data to remote display
        #endif
        if (Command((char*)"save")) SaveValues();
        if (Command((char*)"reset")) ResetValues();
        if (Command((char*)"restart")) while(1); // stay here until the watchdog barks
        if (Command((char*)"ntp")) UpdateTime(); // reload the ntp time
        if (Command((char*)"resetwdc")) eeprom_write_byte ((uint8_t*)EE_CTR, (byte*)0);
        if (Command((char*)"resetday")) eeprom_write_byte ((uint8_t*)EE_RESETDAY, (byte*)day());

//        int i = inString.indexOf("?");
//        if(i != -1) ReadValue(i);
        char *i = strstr(inString, "?");
        if(i != NULL) ReadValue(i);

        ShowStatus(client);
        client.stop();
    }
}

bool Command(char* command)
{
//  int i = inString.indexOf(command);
//  if (i == -1) return false;
  char *i = strstr(inString, command);
  if (i == NULL) return false;

  return true;
}

// void ReadValue(int i)
void ReadValue(char *i)
{
    // String format is "?0=12345"
    //                  "?3=-12345"
    //                  "?G=12345"
    long val = 0;
    bool neg = false;
//    int j = i + 3;
//    int address = inString[i+1];
    char *j = i + 3;
    char *address = i + 1;

    if((address >= '0' && address < '9') || (address >= 'A' && address < 'J')) 
    {
//        char c = inString[j];
        char c = j;
        if(c == '-')
        {
            neg = true;
            j ++;
//            c = inString[j];
            c = j;
        }
        while(c >= '0' && c <= '9')
        {
            val = 10 * val + (c - '0');
            j ++;
//            c = inString[j];
            c = j;
        }
        if(neg) val = -val;
        if(address >= 'A') // Address = 'A...'J' to write the total counters
        {
            sensors[address-'A']->NewTotal(val);
        }
        else // Address = '0'...'9' to write the day counters
        {
            // Let the sensor write the value to eeprom
            sensors[address-'0']->Update(val);
        }
    }
}

Mi sa che ho fatto una gran confusione… Mi sapreste aiutare?

Forse così va bene, ma non sono sicuro… Ora lo sketch viene compilato senza warnings ma non sono sicuro che vada bene.

//String inString = String((char*)"");
char inString[81];

void ServeWebClients()
{
    #if defined(FISH_WIFI)
        FishinoClient client = server.available();  // WiFi
    #elif defined(ARD_ETH)
        EthernetClient client = server.available(); // Wired
    #endif
    if (client) 
    {
//        inString = client.readStringUntil('\n');
        size_t numchars = client.readBytes(inString, 80); 
        inString[numchars] = '\0'; // terminate the string

        client << F("HTTP/1.1 200 OK") << endl;
        client << F("Content-Type: text/html") << endl;
        client << F("Connection: close") << endl << endl;
        #if defined(USE_REM_DISPLAY)
          if (Command((char*)"disp")) SendToremDisplay(sensors); // Send data to remote display
        #endif
        if (Command((char*)"save")) SaveValues();
        if (Command((char*)"reset")) ResetValues();
        if (Command((char*)"restart")) while(1); // stay here until the watchdog barks
        if (Command((char*)"ntp")) UpdateTime(); // reload the ntp time
        if (Command((char*)"resetwdc")) eeprom_write_byte ((uint8_t*)EE_CTR, (byte*)0);
        if (Command((char*)"resetday")) eeprom_write_byte ((uint8_t*)EE_RESETDAY, (byte*)day());

//        int i = inString.indexOf("?");
//        if(i != -1) ReadValue(i);
        char *i = strstr(inString, "?");
        if(i != NULL) ReadValue(i);

        ShowStatus(client);
        client.stop();
    }
}

bool Command(char* command)
{
//  int i = inString.indexOf(command);
//  if (i == -1) return false;
  char *i = strstr(inString, command);
  if (i == NULL) return false;

  return true;
}

// void ReadValue(int i)
void ReadValue(char *i)
{
    // String format is "?0=12345"
    //                  "?3=-12345"
    //                  "?G=12345"
    long val = 0;
    bool neg = false;
//    int j = i + 3;
//    int address = inString[i+1];
    char *j = i + 3;
    char *address = i + 1;

    if((*address >= '0' && *address < '9') || (*address >= 'A' && *address < 'J')) 
    {
//        char c = inString[j];
        char c = *j;
        if(c == '-')
        {
            neg = true;
            j ++;
//            c = inString[j];
            c = *j;
        }
        while(c >= '0' && c <= '9')
        {
            val = 10 * val + (c - '0');
            j ++;
//            c = inString[j];
            c = *j;
        }
        if(neg) val = -val;
        if(*address >= 'A') // Address = 'A...'J' to write the total counters
        {
            sensors[*address-'A']->NewTotal(val);
        }
        else // Address = '0'...'9' to write the day counters
        {
            // Let the sensor write the value to eeprom
            sensors[*address-'0']->Update(val);
        }
    }
}

Ciao, non puoi utilizzare metodi che restituiscono un oggetto String e assegnarlo ad un array di char.
readStringUntil(), mi sembra che restituisca un oggetto string, comunque non puoi assegnare a un array di char utilizzando la sintassi array=stringa.

Se vuoi usare array di char, le stringhe stile C, devi partire con la lettura della stringa carattere per carattere e assegnarli agli elementi dell' array.

Userai il metodo Client.read(). Leggere un carattere da client o leggerlo da seriale non cambia niente, quindi puoi vedere gli esempi "leggere una stringa da seriale" e applicarla nelle tue funzioni.

Poi userai se necessario le funzioni stringa del C, strcmp() per confrontare due stringhe, strlen() lunghezza
ecc..

Devi cambiare la lettura della stringa da client, devi andare a leggere un carattere alla volta. Come detto prendi esempio da lettura stringa da seriale.

A quanto so io la funzione strcmp() restituisce vero anche se le stringhe sono di diversa lunghezza ma quella più corta è identica ai primi caratteri della più lunga.
Ad esempio “assurdo” e “a”.

La Nintendo Wii venne craccata proprio per questo errore.

A me non risulta quest'errore, ho fatto delle prove con il c e il compilatore gcc e il risultati sono corretti, ovvero:

char uno[] = "unoa";
char due[] = "uno";
strcmp(uno,due);
Risultato 1
char uno[] = "uno";
char due[] = "unoa";
strcmp(uno,due);
Risultato -1
char uno[] = "uno";
char due[] = "una";
strcmp(uno,due);
Risultato 1
char uno[] = "uno";
char due[] = "uno";
strcmp(uno,due);
Risultato 0

Sembra rispondere alle specifiche del manuale K&R

Forse il "problema" si presenta con la strncmp passando come terzo parametro la lunghezza della stringa più corta, controllo

Come mi aspettavo, con la strncmp con se viene utilizzata in questo modo:

char uno[] = "uno";
char due[] = "unod";
strncmp(uno,due, strlen(uno));
Risultato 0

Ma è normale, è un errore utilizzare la lunghezza della stringa più corta (sempre dipendentemente da cosa si voglia confrontare ed ottenere), occorre fare una cosa del tipo:

char uno[] = "uno";
char due[] = "unod";
strncmp(uno,due, strlen(uno)<strlen(due)?strlen(due):strlen(uno));
Risultato -100

Risultati sempre in linea con il K&R

Hai ragione.
Il baco era generato dal fatto che venne usato strcmp per la comparazione di hash che potevano quindi anche contenere lo zero, il che non succede per le stringhe vere e proprie che lo zero lo hanno solo alla fine.
http://wiibrew.org/wiki/Signing_bug
Ma hanno usato anche il parametro lunghezza, proprio come hai fatto tu

strncmp(payload_hash, sig_hash, SHA1_LENGTH)

Così mi torna anche per via del controllo della strcmp:

if(s[i] == '\0') return 0;

che è il problema che hai indicato e che è stato sfruttato per la wii

torn24:
Ciao, non puoi utilizzare metodi che restituiscono un oggetto String e assegnarlo ad un array di char.
readStringUntil(), mi sembra che restituisca un oggetto string, comunque non puoi assegnare a un array di char utilizzando la sintassi array=stringa.

Se vuoi usare array di char, le stringhe stile C, devi partire con la lettura della stringa carattere per carattere e assegnarli agli elementi dell' array.

Userai il metodo Client.read(). Leggere un carattere da client o leggerlo da seriale non cambia niente, quindi puoi vedere gli esempi "leggere una stringa da seriale" e applicarla nelle tue funzioni.

Se guardi bene, quella riga è commentata. Come ho scritto nel primo post, ho lasciato il vecchio codice commentato per capire come avevo sostituito quello che c'era con quello nuovo... Tranne nelle ultime righe, dove ho semplicemente aggiunto gli * dove secondo me era necessario senza lasciare la vecchia riga di codice commentata. Sembra che funzioni ma volevo essere sicuro di non aver scritto castronerie...
Grazie.

CrazyHorse80,
scusa se abbiamo divagato ma.... siamo un po' pazzi anche noi!

Una sola nota o curiostà personale: ma nel codice preesistente, che senso ha la prima riga?

String inString = String((char*)"");

Non serve a nulla, basta:

String inString = "";

anzi:

String inString;

docdoc:
Una sola nota o curiostà personale: ma nel codice preesistente, che senso ha la prima riga?

String inString = String((char*)"");

Non serve a nulla, basta:

String inString = "";

anzi:

String inString;

Ciao, il codice originale non era scritto da me ma è uno sketch che ho trovato in rete, da li sono partito e modificandolo radicalmente, ho creato un nuovo sketch che pian piano sto cercando di migliorare. Ho gia trovato diversi errori e bugs nel codice originale che ho corretto e probabilmente ce ne sono di altri... Mi sembrava una buona idea partire da un codice funzionante e modificare ma forse avrei fatto prima a scrivere tutto di sana pianta (e non escludo che prima o poi lo farò), anche perchè ci ho già trascorso decine di ore a modificare e testare cose che credevo funzionanti ed invece non lo erano...
Per le divagazioni, non c'è problema, ho imparato anche da li. :smiley:

CrazyHorse80:
Ciao, il codice originale non era scritto da me ma è uno sketch che ho trovato in rete

Si, si, lo so, non dicevo che l'avessi scritta tu, mi chiedo solo quale mente abbia partorito quell'inizializzazione che a me pare inutile, e perché... :wink: