Trying to use strstr to find character in a string - can't compile

This language is the most convoluted and un-obvious of the dozen or so languages I have written code in in my career. PLEASE, give me IBM assembler. Now there's an easy language.

Anyway... Here's what I am trying to compile. Simple stuff. Can't get past the compiler. (snips - I hope I included everything needed to show what I am doing.)

File webFile;
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char req_index = 0; // index into HTTP_req buffer

char Reqd_File[FN_BUF_SZ] = {0};
char *Filename_Index; // some web site said put in the *
boolean Filename_Found = false;

...snipped code to get the data...

memcpy(Reqd_File, &HTTP_req[4], FN_BUF_SZ); // Get beginning of the filename. Always a /.

Filename_Index = strstr(Reqd_File, " ");

if (Filename_Index) Serial.println(F("Found"));

Reqd_File[Filename_Index] = "\0"; // null terminate the desired string of chars in array

This last statement gets this wonderfully cryptic message:

invalid types 'char[116][char*]' for array subscript

This is so very easy in other languages. Why not in C? What does it want me to do. I have a "GET /filename" line from a browser in the HTTP_req array. Already verified it starts with "GET /". I copy starting at array index 4 to get the front of the filename into a different array of char and then search for a blank (space) to end the filename. Then I can open and send that file. That easy! Right? Can't make it happen!

All help greatly appreciated. C just makes me crazy. I have tried to stay away from it because of it being so very cryptic. To use Arduino, it is required and I have had much success with it. But after many hours of research, I cannot get this to compile. I guess I could write a little routine to implement this but why reinvent the wheel? There must be a way to do this.

Mike

Please edit your post, select the code, and put it between [code] ... [/code] tags.

You can do that by hitting the "Code" icon above the posting area. It is the first icon, with the symbol: </>

Reqd_File[Filename_Index] = "\0";         // null terminate the desired string of chars in array

You have to pay attention to quotes. That is probably meant to be:

Reqd_File[Filename_Index] = '\0';         // null terminate the desired string of chars in array
Reqd_File[Filename_Index] = "\0";

Did you mean

Reqd_File[Filename_Index] = '\0';

?

Edit: Curses!

You might be interested in Tiny web server for Arduino or similar.

AWOL:

Reqd_File[Filename_Index] = "\0";

Did you mean

Reqd_File[Filename_Index] = '\0';

?

Ninjad you by one minute!

I went for a cup of tea.

Nick Gammon - the code I showed in the post was NOT MEANT to be copied and run. So I did NOT put it in code window. That would be confusing to most people.

It was only snippets of code from the program illustrating problems. I have tried every combination of quotes. I will go back and try the single quotes again. So far, nothing works.

Result:

Reqd_File[Filename_Index] = '\0';

Gives the same cryptic message: invalid types 'char[116][char*] for array subscript.

Did you try this before submitting this answer?

Can we now focus on the actual problem, please?

Here's part 1 of the code. It went beyond 9000 bytes.

/*--------------------------------------------------------------
  Program:      eth_websrv_SD_image

  Description:  Arduino web server that serves up a basic web
                page that displays an image.

  Hardware:     Arduino Uno and official Arduino Ethernet
                shield. Should work with other Arduinos and
                compatible Ethernet shields.
                2Gb micro SD card formatted FAT16

  Software:     Developed using Arduino 1.0.5 software
                Should be compatible with Arduino 1.0 +

                Requires index.htm, page2.htm and pic.jpg to be
                on the micro SD card in the Ethernet shield
                micro SD card socket.

  References:   - WebServer example by David A. Mellis and
                  modified by Tom Igoe
                - SD card examples by David A. Mellis and
                  Tom Igoe
                - Ethernet library documentation:
                  http://arduino.cc/en/Reference/Ethernet
                - SD Card library documentation:
                  http://arduino.cc/en/Reference/SD

  Date:         7 March 2013
  Modified:     17 June 2013

  Author:       W.A. Smith, http://startingelectronics.org
--------------------------------------------------------------*/

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

// size of buffer used to capture HTTP requests
#define REQ_BUF_SZ   120
#define MAX_TO_SAVE REQ_BUF_SZ-1
#define FN_BUF_SZ REQ_BUF_SZ-4

// MAC address from Ethernet shield sticker under board
byte MAC[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress MyDNS(96, 92, 96, 26);      // the DNS server IP
IPAddress MyIP(96, 92, 96, 29);       // Assigned IP address
IPAddress Gateway(96, 92, 96, 30);    // Router's gateway address
IPAddress Subnet(255, 255, 255, 248); // Subnet mask
EthernetServer server(80);            // create a server on port 80
File webFile;
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char req_index = 0;              // index into HTTP_req buffer

char Reqd_File[FN_BUF_SZ] = {0};
char *Filename_Index;
boolean Filename_Found = false;
boolean currentLineIsBlank;

byte buf[512];                   // Place to read input file chunks

void setup()
{
  // disable Ethernet chip
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);

  Serial.begin(9600);       // for debugging

  // initialize SD card
  Serial.println(F("Initializing SD card..."));
  if (!SD.begin(4)) {
    Serial.println(F("ERROR - SD card initialization failed!"));
    return;    // init failed
  }
  Serial.println(F("SUCCESS - SD card initialized."));
  // check for index.htm file
  if (!SD.exists("index.htm")) {
    Serial.println(F("ERROR - Can't find index.htm file!"));
    return;  // can't find index file
  }
  Serial.println(F("SUCCESS - Found index.htm file."));

  //    Ethernet.begin(MAC, MyIP, MyDNS, Gateway, Subnet);  // Use all parms
  Serial.println(F("\nNow trying to connect Ethernet"));
  if (Ethernet.begin(MAC) == 0)
    Serial.println(F("Failed to configure Ethernet using DHCP."));
  else
    Serial.println(F("DHCP successful"));

  Ethernet.begin(MAC);                                  // initialize Ethernet device with DHCP
  server.begin();                                       // start to listen for clients
  delay(100);
  Serial.print("Server (me): ");
  Serial.println(Ethernet.localIP());
  Serial.print("Subnet Mask: ");
  Serial.println(Ethernet.subnetMask());
  Serial.print("DNSServer is ");
  Serial.println(Ethernet.dnsServerIP());
  Serial.print("Gateway IP:  ");
  Serial.println(Ethernet.gatewayIP());
  Serial.println("");  // Spacing
}

void loop()
{
  EthernetClient client = server.available();  // try to get client

  if (client) {  // got client?
    currentLineIsBlank = true;
    Filename_Found = false;
    while (client.connected()) {
      if (client.available()) {   // client data available to read
        char c = client.read();   // read 1 byte (character) from client
        // buffer first part of HTTP request in HTTP_req array (string)
        // Because only the buffersize (REQ_BUF_SZ) -1 is kept, there can be no overflow
        // HEY MICROSOFT!!!  LISTENING?!?!?!?!?!?!?!
        // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
        if (req_index < (MAX_TO_SAVE)) {
          HTTP_req[req_index] = c;          // save HTTP request character
          req_index++;                      // Bump to next array location.
        }
        //        if (req_index > REQ_BUF_SZ) {     // Cannot be overflow.  No use to check.
        //          client.println("HTTP/1.0 414 Request Too Long");
        //          client.println("Conection:close");
        //          client.println();
        //          return;
        //        }
        // print HTTP request character to serial monitor
        Serial.print(c); Serial.print(F("."));
        // last line of client request is blank and ends with \n
        // respond to client only after last line received

}

Here's part 2.

        if (c == '\n' && currentLineIsBlank) {
          Serial.println(F("Here's what I saw: -----------------------------------------------"));
          Serial.println(HTTP_req);
          Serial.println(F("------------------------------------------------------------------"));
          // open requested web page file
          if (StrMatchLeft(HTTP_req, "GET /")) {  // || StrMatchLeft(HTTP_req, "GET /index.htm")) {
            Serial.println(F("Found GET / command."));
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html");
            client.println("Connnection: close");
            client.println();
            memcpy(Reqd_File, &HTTP_req[4], FN_BUF_SZ);
            Serial.println(F("Here's the command (raw): ----------------------------------------"));
            Serial.println(Reqd_File);
            Serial.println(F("------------------------------------------------------------------"));
            Filename_Index = strstr(Reqd_File, " ");
            if (Filename_Index) Serial.println(F("Found"));
            Serial.print(F("End of filename in column: "));
            Serial.println(Filename_Index);
            Reqd_File[Filename_Index] = '\0';
            //            Serial.print(F("Truncated down" "));
            //            Serial.println(Reqd_File);
            webFile = SD.open("index.htm");        // open web page file
          }
          else if (StrMatchLeft(HTTP_req, "GET /page2.htm")) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html");
            client.println("Connnection: close");
            client.println();
            webFile = SD.open("page2.htm");        // open web page file
          }
          else if (StrMatchLeft(HTTP_req, "GET /pic.jpg")) {
            webFile = SD.open("pic.jpg");
            if (webFile) {
              client.println("HTTP/1.1 200 OK");
              client.println();
            }
          }
          if (webFile) {
            Serial.print(F("Reading file: "));
            Serial.println(Reqd_File);
            while (1) {
              int n = webFile.available();
              if (n == 0) break;
              if (n > 512) n = 512;
              webFile.read(buf, n);
              client.write(buf, n);
            }
            webFile.close();
          }
          // reset buffer index and all buffer elements to 0
          req_index = 0;
          Filename_Index = 0;
          StrClear(HTTP_req, REQ_BUF_SZ);
          StrClear(Reqd_File, REQ_BUF_SZ);
          break;
        }
        // every line of text received from the client ends with \r\n
        if (c == '\n') {
          //last character on line of received text
          //starting new line with next character read
          currentLineIsBlank = true;
        }
        else if (c != '\r') {  // a text character was received from client
          currentLineIsBlank = false;
        }
      }  // end if (client.available())
    }    // end while (client.connected())
    delay(1);      // give the web browser time to receive the data
    client.stop(); // close the connection
  }                // end if (client)
}

// sets every element of str to 0 (clears array)
void StrClear(char *str, char length)
{
  for (int i = 0; i < length; i++) str[i] = 0;
}

// searches for the string sfind in the string str
// returns 1 if string found
// returns 0 if string not found
//char StrContains(char *searched, char *sought)
//{
//  char found = 0;
//  char index = 0;
//  char len;
//
//  len = strlen(searched);  // the string being searched
//
//  if (strlen(sought) > len) {  // is sought longer than searched?  That's wrong!
//    return 0;
//  }
//  while (index < len) {
//    if (searched[index] == sought[found]) {
//      found++;
//      if (strlen(sought) == found) {
//        return 1;
//      }
//    }
//    else {
//      found = 0;
//    }
//    index++;
//  }
//  return 0;
//}

// Search Haystack for Needle starting in position 1 only.  If no match before the length of Needle, return 0.
// If there is a match for the length of Needle, then we declare a match.
char StrMatchLeft(char *Haystack, char *Needle)
{
  char HaystackPtr = 0;
  char NeedlePtr = 0;
  char HaystackLen;

  HaystackLen = strlen(Haystack);                      // length the string being searched
  if (strlen(Needle) > HaystackLen)  return 0;         // is sought longer than searched?  That's wrong!  Can't be a match.

  while (HaystackPtr < HaystackLen) {                  // search whole length of searched string
    if (Haystack[HaystackPtr] == Needle[NeedlePtr]) {  // if characters are equal,
      NeedlePtr++;                                     // more to next sought byte
      if (strlen(Needle) == NeedlePtr) return 1;       // if we have matches for the entore length of sought, we are done.
    } else {
      return 0;  // got a partial match but it did not last for the runlength of sought.  Return no match.
    }
    HaystackPtr++;
  }
  return 0;      // Should never get here.  Maybe...  Right?  Either we exited with mismatch or Needle length ran out.  Right???

the code I showed in the post was NOT MEANT to be copied and run. So I did NOT put it in code window. That would be confusing to most people.

No one would be confused. Failure to use code tags makes the code harder to read.

I got your Tiny example and the library installed and running. It does nothing except say "OK, Done." I have a good index.htm file on the SD card which I need to access. That is working. I just need to be able to send the other files requested in index.htm.

I am looking for or to write a fully functioning web file server on Arduino. It does not need cookies and a lot of fluff, just serve the files named on the "GET /" commands.

If there is one already written and working, I would love to see it. Else, I need some help getting this one going. I will be quite glad to post the results. Just need to have something that works, first.

And this cryptic compiler error has me totally stopped.

I can code normal C stuff and have dozens of examples of what I have done but this one has me totally stopped with this message. There is something wrong with the definitions of stuff at the top but I have not been able to find anything on the web (this is my third day of looking) to help me understand how to do this simple task.

Mike Morrow

invalid types 'char[116][char*] for array subscript.
char *Filename_Index;
...
Filename_Index = strstr(Reqd_File, " ");
...
Reqd_File[Filename_Index] = '\0';

You can't access an array index using a char* (pointer) variable.

You can do something like this to get the index:

char *Filename_Index;
...
Filename_Index = strstr(Reqd_File, " ");
...
int ArrayIndex = 0;
if (Filename_Index)
 ArrayIndex = Filename_Index - Reqd_File;
 
Reqd_File[ArrayIndex] = '\0';

Subtracting Reqd_File from Filename_Index will return which index from Reqd_File the Filename_Index is pointing.

The below post has arduino server code that sends a couple of files from the SD card back to the client. All the files needed to try the setup are included in the attached zip file attached to the post.

http://forum.arduino.cc/index.php?topic=279849.msg1970392#msg1970392

MikeyMoMo:
Nick Gammon - the code I showed in the post was NOT MEANT to be copied and run. So I did NOT put it in code window. That would be confusing to most people.

Well I prefer a Minimal, Complete, and Verifiable example - so it would be courteous to supply one.

It was only snippets of code from the program illustrating problems.

Snippets, eh?

http://snippets-r-us.com/

Did you try this before submitting this answer?

You want me to spend 10 minutes forcing your code into some sort of compilable form? Why don't you do that?

Can we now focus on the actual problem, please?

Yes, when you put it into code tags. Without code tags things like [ i ] turn into italics, all sorts of weird things happen, and it is hard to read.

Here's part 1 of the code. It went beyond 9000 bytes.

Fortunately you can attach code to posts, which you would have found out if you read the posting guidelines.

Read this before posting a programming question

How to use this forum

Decided I had to fix it myself. Not complete but somewhat working.

/*--------------------------------------------------------------
  Program:      Webserve from SD w/images

  Description:  Arduino web server that serves up web pages and images.

  Hardware:     Arduino Uno and official Arduino Ethernet
                shield. Should work with other Arduinos and
                compatible Ethernet shields.
                2Gb or larger micro SD card formatted FAT16/32

  Software:     Developed using Arduino 1.6.5 software
                Should be compatible with Arduino 1.0 +

                Requires index.htm, page2.htm and pic.jpg to be
                on the micro SD card in the Ethernet shield
                micro SD card socket.

  References:   - WebServer example by David A. Mellis and
                  modified by Tom Igoe
                - SD card examples by David A. Mellis and
                  Tom Igoe
                - Ethernet library documentation:
                  http://arduino.cc/en/Reference/Ethernet
                - SD Card library documentation:
                  http://arduino.cc/en/Reference/SD

  Date:         7 March 2013
  Modified:     17 June 2013
                17 Aug  2015 MDM
  Author:       
                Basics: W.A. Smith, http://startingelectronics.org
                Expanded function: Mike Morrow http://ILikeTheInternet.com
--------------------------------------------------------------*/

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

// size of buffer used to capture HTTP requests
#define REQ_BUF_SZ   120
#define MAX_TO_SAVE REQ_BUF_SZ-1
#define FN_BUF_SZ REQ_BUF_SZ-4

// MAC address from Ethernet shield sticker under board
byte MAC[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress MyDNS(96, 92, 96, 26);      // the DNS server IP
IPAddress MyIP(96, 92, 96, 29);       // Assigned IP address
IPAddress Gateway(96, 92, 96, 30);    // Router's gateway address
IPAddress Subnet(255, 255, 255, 248); // Subnet mask
EthernetServer server(80);            // create a server on port 80
File webFile;
char c;
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char req_index = 0;              // index into HTTP_req buffer
char index_htm[10] = "index.htm";
char Reqd_File[FN_BUF_SZ] = {0};
char Filename_Index;
boolean Filename_Found = false;
boolean currentLineIsBlank;

byte buf[512];                   // Place to read input file chunks

void setup()
{
//disable Ethernet chip
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);

  Serial.begin(57600);       // for debugging

//initialize SD card
  Serial.println(F("Initializing SD card..."));
  if (!SD.begin(4)) {
    Serial.println(F("ERROR - SD card initialization failed!"));
    return;    // init failed
  }
  Serial.println(F("SUCCESS - SD card initialized."));
//check for index.htm file
  if (!SD.exists("index.htm")) {
    Serial.println(F("ERROR - Can't find index.htm file!"));
    return;  // can't find index file
  }
  Serial.println(F("SUCCESS - Found index.htm file."));

//Ethernet.begin(MAC, MyIP, MyDNS, Gateway, Subnet);  // Use all parms
  Serial.println(F("\nNow trying to connect Ethernet"));
  if (Ethernet.begin(MAC) == 0)
    Serial.println(F("Failed to configure Ethernet using DHCP."));
  else
    Serial.println(F("DHCP successful"));

  Ethernet.begin(MAC);                                  // initialize Ethernet device with DHCP
  server.begin();                                       // start to listen for clients
  delay(100);
}

void loop()
{
  EthernetClient client = server.available();  // try to get client

  if (client) {  // got client?
    currentLineIsBlank = true;
    Filename_Found = false;
    while (client.connected()) {
      if (client.available()) {   // client data available to read
        c = client.read();   // read 1 byte (character) from client
      //buffer first part of HTTP request in HTTP_req array (string)
      //Because only the buffersize (REQ_BUF_SZ) -1 is kept, there can be no overflow
      //HEY MICROSOFT!!!  LISTENING?!?!?!?!?!?!?!
      //leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
        if (req_index < (MAX_TO_SAVE)) {
          HTTP_req[req_index] = c;          // save HTTP request character
          req_index++;                      // Bump to next array location.
        //print HTTP request character to serial monitor
//Serial.print(c);
        //last line of client request is blank and ends with \n
        //respond to client only after last line received
        if (c == '\n' && currentLineIsBlank) {
          //open requested web page file
          if (StrMatchLeft(HTTP_req, "GET /")) {  // || StrMatchLeft(HTTP_req, "GET /index.htm")) {
            Serial.println(F("Found GET / command."));
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html");
            client.println("Connnection: close");
            client.println();
            memcpy(Reqd_File, &HTTP_req[4], FN_BUF_SZ);
            Filename_Index = FindCharAfter(Reqd_File," ",0);  // Starting in array location 0, find first 
            Serial.print(F("Ending space "));
            if (Filename_Index == 0) Serial.print(F("not "));
            Reqd_File[Filename_Index] = '\0';
            Serial.println(Reqd_File);
            if (Filename_Index == 1) {
              StrClear(Reqd_File,FN_BUF_SZ);
              memcpy(Reqd_File,index_htm,sizeof(index_htm));
            }
            webFile = SD.open(Reqd_File);        // open web page file
          }
          if (webFile) {
            Serial.print(F("Reading file: "));
            Serial.println(Reqd_File);
            while (1) {
              int n = webFile.available();
              if (n == 0) break;
              if (n > 512) n = 512;
              webFile.read(buf, n);
              client.write(buf, n);
            }
            webFile.close();
          }
          // reset buffer index and all buffer elements to 0
          req_index = 0;
          Filename_Index = 0;
          StrClear(HTTP_req, REQ_BUF_SZ);
          StrClear(Reqd_File, REQ_BUF_SZ);
          break;
        }
        // every line of text received from the client ends with \r\n
        if (c == '\n') {
        //last character on line of received text
        //starting new line with next character read
          currentLineIsBlank = true;
        }
        else if (c != '\r') {  // a text character was received from client
          currentLineIsBlank = false;
        }
      }  // end if (client.available())
    }    // end while (client.connected())
    delay(1);      // give the web browser time to receive the data
    client.stop(); // close the connection
  }                // end if (client)
}

// sets every element of str to 0 (clears array)
void StrClear(char *str, char length)
{
  for (int i = 0; i < length; i++) str[i] = 0;
}

// Search Haystack for Needle starting in position 1 only.  If no match before the length of Needle, return 0.
// If there is a match for the length of Needle, then we declare a match.
char StrMatchLeft(char *Haystack, char *Needle)
{
  char HaystackPtr = 0;
  char NeedlePtr = 0;
  char HaystackLen;

  HaystackLen = strlen(Haystack);                      // length the string being searched
  if (strlen(Needle) > HaystackLen)  return 0;         // is sought longer than searched?  That's wrong!  Can't be a match.

  while (HaystackPtr < HaystackLen) {                  // search whole length of searched string
    if (Haystack[HaystackPtr] == Needle[NeedlePtr]) {  // if characters are equal,
      NeedlePtr++;                                     // more to next sought byte
      if (strlen(Needle) == NeedlePtr) return 1;       // if we have matches for the entore length of sought, we are done.
    } else {
      return 0;  // got a partial match but it did not last for the runlength of sought.  Return no match.
    }
    HaystackPtr++;
  }
  return 0;      // Should never get here.  Maybe...  Right?  Either we exited with mismatch or Needle length ran out.  Right???
}

char FindCharAfter(char *Haystack, char *Needle, char StartByte)
{
  char HaystackPtr = StartByte;
  char HaystackLen;

  HaystackLen = strlen(Haystack);                      // length the string being searched
  if (HaystackLen < 1) return 0;                       // Can't be too short

  while (HaystackPtr < HaystackLen) {
    if (Haystack[HaystackPtr] == Needle[0]) return HaystackPtr;
    HaystackPtr++;
  }
}

PLEASE, give me IBM assembler. Now there's an easy language.

There were many IBM assemblers - which one were you thinking of?
Assembler for the IBM 704 gave us LISP.
Now, there's a easy language.

That would be confusing to most people.

So, code that isn't the same as the code which produces the error you describe isn't confusing?

This language is the most convoluted and un-obvious of the dozen or so languages I have written code in in my career

And yet, it's one of the most ubiquitous.

MikeyMoMo:
That would be confusing to most people.

We aren't most people. :wink: