Related
I have a .csv file:
lp;imie;nazwisko;ulica;numer;kod;miejscowosc;telefon;email;data_ur
1;Jan;Kowalski;ul. Nowa;1a;11-234;Budry;123-123-456;jan#go.xxx;1980.05.13
2;Jerzy;Nowak;ul. Konopnicka;13a/3;00-900;Lichowice;(55)333-44-55;jer#wu.to;1990.03.23
And I need to read this in C. I have some code, but only for the connection.
Hopefully this would get you started
See it live on http://ideone.com/l23He (using stdin)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* getfield(char* line, int num)
{
const char* tok;
for (tok = strtok(line, ";");
tok && *tok;
tok = strtok(NULL, ";\n"))
{
if (!--num)
return tok;
}
return NULL;
}
int main()
{
FILE* stream = fopen("input", "r");
char line[1024];
while (fgets(line, 1024, stream))
{
char* tmp = strdup(line);
printf("Field 3 would be %s\n", getfield(tmp, 3));
// NOTE strtok clobbers tmp
free(tmp);
}
}
Output:
Field 3 would be nazwisko
Field 3 would be Kowalski
Field 3 would be Nowak
The following code is in plain c language and handles blank spaces.
It only allocates memory once, so one free() is needed, for each processed line.
http://ideone.com/mSCgPM
/* Tiny CSV Reader */
/* Copyright (C) 2015, Deligiannidis Konstantinos
This program 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 program 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 this program. If not, see <http://w...content-available-to-author-only...u.org/licenses/>. */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* For more that 100 columns or lines (when delimiter = \n), minor modifications are needed. */
int getcols( const char * const line, const char * const delim, char ***out_storage )
{
const char *start_ptr, *end_ptr, *iter;
char **out;
int i; //For "for" loops in the old c style.
int tokens_found = 1, delim_size, line_size; //Calculate "line_size" indirectly, without strlen() call.
int start_idx[100], end_idx[100]; //Store the indexes of tokens. Example "Power;": loc('P')=1, loc(';')=6
//Change 100 with MAX_TOKENS or use malloc() for more than 100 tokens. Example: "b1;b2;b3;...;b200"
if ( *out_storage != NULL ) return -4; //This SHOULD be NULL: Not Already Allocated
if ( !line || !delim ) return -1; //NULL pointers Rejected Here
if ( (delim_size = strlen( delim )) == 0 ) return -2; //Delimiter not provided
start_ptr = line; //Start visiting input. We will distinguish tokens in a single pass, for good performance.
//Then we are allocating one unified memory region & doing one memory copy.
while ( ( end_ptr = strstr( start_ptr, delim ) ) ) {
start_idx[ tokens_found -1 ] = start_ptr - line; //Store the Index of current token
end_idx[ tokens_found - 1 ] = end_ptr - line; //Store Index of first character that will be replaced with
//'\0'. Example: "arg1||arg2||end" -> "arg1\0|arg2\0|end"
tokens_found++; //Accumulate the count of tokens.
start_ptr = end_ptr + delim_size; //Set pointer to the next c-string within the line
}
for ( iter = start_ptr; (*iter!='\0') ; iter++ );
start_idx[ tokens_found -1 ] = start_ptr - line; //Store the Index of current token: of last token here.
end_idx[ tokens_found -1 ] = iter - line; //and the last element that will be replaced with \0
line_size = iter - line; //Saving CPU cycles: Indirectly Count the size of *line without using strlen();
int size_ptr_region = (1 + tokens_found)*sizeof( char* ); //The size to store pointers to c-strings + 1 (*NULL).
out = (char**) malloc( size_ptr_region + ( line_size + 1 ) + 5 ); //Fit everything there...it is all memory.
//It reserves a contiguous space for both (char**) pointers AND string region. 5 Bytes for "Out of Range" tests.
*out_storage = out; //Update the char** pointer of the caller function.
//"Out of Range" TEST. Verify that the extra reserved characters will not be changed. Assign Some Values.
//char *extra_chars = (char*) out + size_ptr_region + ( line_size + 1 );
//extra_chars[0] = 1; extra_chars[1] = 2; extra_chars[2] = 3; extra_chars[3] = 4; extra_chars[4] = 5;
for ( i = 0; i < tokens_found; i++ ) //Assign adresses first part of the allocated memory pointers that point to
out[ i ] = (char*) out + size_ptr_region + start_idx[ i ]; //the second part of the memory, reserved for Data.
out[ tokens_found ] = (char*) NULL; //[ ptr1, ptr2, ... , ptrN, (char*) NULL, ... ]: We just added the (char*) NULL.
//Now assign the Data: c-strings. (\0 terminated strings):
char *str_region = (char*) out + size_ptr_region; //Region inside allocated memory which contains the String Data.
memcpy( str_region, line, line_size ); //Copy input with delimiter characters: They will be replaced with \0.
//Now we should replace: "arg1||arg2||arg3" with "arg1\0|arg2\0|arg3". Don't worry for characters after '\0'
//They are not used in standard c lbraries.
for( i = 0; i < tokens_found; i++) str_region[ end_idx[ i ] ] = '\0';
//"Out of Range" TEST. Wait until Assigned Values are Printed back.
//for ( int i=0; i < 5; i++ ) printf("c=%x ", extra_chars[i] ); printf("\n");
// *out memory should now contain (example data):
//[ ptr1, ptr2,...,ptrN, (char*) NULL, "token1\0", "token2\0",...,"tokenN\0", 5 bytes for tests ]
// |__________________________________^ ^ ^ ^
// |_______________________________________| | |
// |_____________________________________________| These 5 Bytes should be intact.
return tokens_found;
}
int main()
{
char in_line[] = "Arg1;;Th;s is not Del;m;ter;;Arg3;;;;Final";
char delim[] = ";;";
char **columns;
int i;
printf("Example1:\n");
columns = NULL; //Should be NULL to indicate that it is not assigned to allocated memory. Otherwise return -4;
int cols_found = getcols( in_line, delim, &columns);
for ( i = 0; i < cols_found; i++ ) printf("Column[ %d ] = %s\n", i, columns[ i ] ); //<- (1st way).
// (2nd way) // for ( i = 0; columns[ i ]; i++) printf("start_idx[ %d ] = %s\n", i, columns[ i ] );
free( columns ); //Release the Single Contiguous Memory Space.
columns = NULL; //Pointer = NULL to indicate it does not reserve space and that is ready for the next malloc().
printf("\n\nExample2, Nested:\n\n");
char example_file[] = "ID;Day;Month;Year;Telephone;email;Date of registration\n"
"1;Sunday;january;2009;123-124-456;jitter#go.xyz;2015-05-13\n"
"2;Monday;March;2011;(+30)333-22-55;buffer#wl.it;2009-05-23";
char **rows;
int j;
rows = NULL; //getcols() requires it to be NULL. (Avoid dangling pointers, leaks e.t.c).
getcols( example_file, "\n", &rows);
for ( i = 0; rows[ i ]; i++) {
{
printf("Line[ %d ] = %s\n", i, rows[ i ] );
char **columnX = NULL;
getcols( rows[ i ], ";", &columnX);
for ( j = 0; columnX[ j ]; j++) printf(" Col[ %d ] = %s\n", j, columnX[ j ] );
free( columnX );
}
}
free( rows );
rows = NULL;
return 0;
}
A complete example which leaves the fields as NULL-terminated strings in the original input buffer and provides access to them via an array of char pointers. The CSV processor has been confirmed to work with fields enclosed in "double quotes", ignoring any delimiter chars within them.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// adjust BUFFER_SIZE to suit longest line
#define BUFFER_SIZE 1024 * 1024
#define NUM_FIELDS 10
#define MAXERRS 5
#define RET_OK 0
#define RET_FAIL 1
#define FALSE 0
#define TRUE 1
// char* array will point to fields
char *pFields[NUM_FIELDS];
// field offsets into pFields array:
#define LP 0
#define IMIE 1
#define NAZWISKo 2
#define ULICA 3
#define NUMER 4
#define KOD 5
#define MIEJSCOw 6
#define TELEFON 7
#define EMAIL 8
#define DATA_UR 9
long loadFile(FILE *pFile, long *errcount);
static int loadValues(char *line, long lineno);
static char delim;
long loadFile(FILE *pFile, long *errcount){
char sInputBuf [BUFFER_SIZE];
long lineno = 0L;
if(pFile == NULL)
return RET_FAIL;
while (!feof(pFile)) {
// load line into static buffer
if(fgets(sInputBuf, BUFFER_SIZE-1, pFile)==NULL)
break;
// skip first line (headers)
if(++lineno==1)
continue;
// jump over empty lines
if(strlen(sInputBuf)==0)
continue;
// set pFields array pointers to null-terminated string fields in sInputBuf
if(loadValues(sInputBuf,lineno)==RET_FAIL){
(*errcount)++;
if(*errcount > MAXERRS)
break;
} else {
// On return pFields array pointers point to loaded fields ready for load into DB or whatever
// Fields can be accessed via pFields, e.g.
printf("lp=%s, imie=%s, data_ur=%s\n", pFields[LP], pFields[IMIE], pFields[DATA_UR]);
}
}
return lineno;
}
static int loadValues(char *line, long lineno){
if(line == NULL)
return RET_FAIL;
// chop of last char of input if it is a CR or LF (e.g.Windows file loading in Unix env.)
// can be removed if sure fgets has removed both CR and LF from end of line
if(*(line + strlen(line)-1) == '\r' || *(line + strlen(line)-1) == '\n')
*(line + strlen(line)-1) = '\0';
if(*(line + strlen(line)-1) == '\r' || *(line + strlen(line)-1 )== '\n')
*(line + strlen(line)-1) = '\0';
char *cptr = line;
int fld = 0;
int inquote = FALSE;
char ch;
pFields[fld]=cptr;
while((ch=*cptr) != '\0' && fld < NUM_FIELDS){
if(ch == '"') {
if(! inquote)
pFields[fld]=cptr+1;
else {
*cptr = '\0'; // zero out " and jump over it
}
inquote = ! inquote;
} else if(ch == delim && ! inquote){
*cptr = '\0'; // end of field, null terminate it
pFields[++fld]=cptr+1;
}
cptr++;
}
if(fld > NUM_FIELDS-1){
fprintf(stderr, "Expected field count (%d) exceeded on line %ld\n", NUM_FIELDS, lineno);
return RET_FAIL;
} else if (fld < NUM_FIELDS-1){
fprintf(stderr, "Expected field count (%d) not reached on line %ld\n", NUM_FIELDS, lineno);
return RET_FAIL;
}
return RET_OK;
}
int main(int argc, char **argv)
{
FILE *fp;
long errcount = 0L;
long lines = 0L;
if(argc!=3){
printf("Usage: %s csvfilepath delimiter\n", basename(argv[0]));
return (RET_FAIL);
}
if((delim=argv[2][0])=='\0'){
fprintf(stderr,"delimiter must be specified\n");
return (RET_FAIL);
}
fp = fopen(argv[1] , "r");
if(fp == NULL) {
fprintf(stderr,"Error opening file: %d\n",errno);
return(RET_FAIL);
}
lines=loadFile(fp,&errcount);
fclose(fp);
printf("Processed %ld lines, encountered %ld error(s)\n", lines, errcount);
if(errcount>0)
return(RET_FAIL);
return(RET_OK);
}
Use fscanf to read the file until you encounter ';' or \n, then just skip it with fscanf(f, "%*c").
int main()
{
char str[128];
int result;
FILE* f = fopen("test.txt", "r");
/*...*/
do {
result = fscanf(f, "%127[^;\n]", str);
if(result == 0)
{
result = fscanf(f, "%*c");
}
else
{
//Put here whatever you want to do with your value.
printf("%s\n", str);
}
} while(result != EOF);
return 0;
}
This code is fairly simple, but effective. It parses comma-separated files with parenthesis. You can easily modify it to suit your needs.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
// argv[1] path to csv file
// argv[2] number of lines to skip
// argv[3] length of longest value (in characters)
FILE *pfinput;
unsigned int nSkipLines, currentLine, lenLongestValue;
char *pTempValHolder;
int c;
unsigned int vcpm; // Value character marker
int QuotationOnOff; // 0 - off, 1 - on
nSkipLines = atoi(argv[2]);
lenLongestValue = atoi(argv[3]);
pTempValHolder = (char*)malloc(lenLongestValue);
if(pfinput = fopen(argv[1], "r")) {
rewind(pfinput);
currentLine = 1;
vcpm = 0;
QuotationOnOff = 0;
// currentLine > nSkipLines condition
// skips / ignores first argv[2] lines
while((c = fgetc(pfinput)) != EOF)
{
switch(c)
{
case ',':
if(!QuotationOnOff && currentLine > nSkipLines)
{
pTempValHolder[vcpm] = '\0';
printf("%s,", pTempValHolder);
vcpm = 0;
}
break;
case '\n':
if(currentLine > nSkipLines)
{
pTempValHolder[vcpm] = '\0';
printf("%s\n", pTempValHolder);
vcpm = 0;
}
currentLine++;
break;
case '\"':
if(currentLine > nSkipLines)
{
if(!QuotationOnOff) {
QuotationOnOff = 1;
pTempValHolder[vcpm] = c;
vcpm++;
} else {
QuotationOnOff = 0;
pTempValHolder[vcpm] = c;
vcpm++;
}
}
break;
default:
if(currentLine > nSkipLines)
{
pTempValHolder[vcpm] = c;
vcpm++;
}
break;
}
}
fclose(pfinput);
free(pTempValHolder);
}
return 0;
}
#include <conio.h>
#include <stdio.h>
#include <string.h>
// Driver Code
int main()
{
// Substitute the full file path
// for the string file_path
FILE* fp = fopen("Movie.csv", "r");
char *wrds[40];
if (!fp)
printf("Can't open file\n");
else {
// Here we have taken size of
// array 1024 you can modify it
char buffer[1024];
int row = 0;
int column = 0;
while (fgets(buffer, 1024, fp)) {
column = 0;
row++;
// To avoid printing of column
// names in file can be changed
// according to need
if (row == 1)
continue;
// Splitting the data
char* value = strtok(buffer, ", ");
while (value) {
// Column 1
if (column == 0) {
printf("Name :");
}
// Column 2
if (column == 1) {
printf("\tAccount No. :");
}
// Column 3
if (column == 2) {
printf("\tAmount :");
}
printf("%s", value);
wrds[column] = value;
value = strtok(NULL, ", ");
column++;
}
printf("\n");
}
// Close the file
fclose(fp);
}
getchar();
return 0;
}
I'm trying to send a JSON to a ESP32 and set the value to a variable, for the first 3 variables it works fine, but for some reason it skips the last one. Right now it's sent in an array, but when it's not in an array and I make it a JSONObject instead of a JSONArray it even skips the last 2 values.
When trying a hardcoded JSON it works fine though.
Here is the code:
#include <Arduino.h>
#include <EEPROM.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <NeoPixelBus.h>
#include <AsyncJson.h>
#include <ArduinoJson.h>
#define EEPROM_SIZE 512
const int powerStateAddress = 0;
const int groupNumberAddress = 2;
const uint16_t pixelCount = 82;
const uint pixelPin = 17;
const uint relayPin = 26;
const char* ssid = "";
const char* password = "";
AsyncWebServer server(80);
const size_t jsonCapacity = JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(4) + 70;
int powerState;
int groupNumber;
int colorSaturation = 255;
int greenValue;
int redValue;
int blueValue;
int whiteValue;
NeoPixelBus<NeoGrbwFeature, NeoEsp32I2s1800KbpsMethod> strip(pixelCount, pixelPin);
RgbwColor green(colorSaturation, 0, 0, 0);
RgbwColor red(0, colorSaturation, 0, 0);
RgbwColor blue(0, 0, colorSaturation, 0);
RgbwColor white(0, 0, 0, colorSaturation);
RgbwColor black(0);
void setGroupNumber(DynamicJsonDocument json) {
groupNumber = json["groupNumber"];
EEPROM.write(groupNumberAddress, groupNumber);
EEPROM.commit();
}
void setColor() {
for(uint16_t pixel = 0; pixel < pixelCount; pixel++) {
strip.SetPixelColor(pixel, RgbwColor(greenValue, redValue, blueValue, whiteValue));
}
}
void setColorValues(DynamicJsonDocument json) {
JsonArray colorValues = json["colorValues"];
if(greenValue != colorValues[0]) {
greenValue = colorValues[0];
}
if(redValue != colorValues[1]) {
redValue = colorValues[1];
}
if(blueValue != colorValues[2]) {
blueValue = colorValues[2];
}
if(whiteValue != colorValues[3]) {
whiteValue = colorValues[3];
}
setColor();
}
void setBrightness(DynamicJsonDocument json) {
colorSaturation = json["brightness"];
setColor();
}
DynamicJsonDocument parseData(AsyncWebServerRequest *request, uint8_t *data, String endpoint) {
DynamicJsonDocument doc(jsonCapacity);
DeserializationError err = deserializeJson(doc, data);
Serial.println(serializeJson(doc, Serial));
if(err) {
request->send(400, "text/plain", "err on" + endpoint);
} else {
request->send(200, "application/json", "{'msg': 'OK'}");
}
return doc;
}
void setup() {
Serial.begin(115200);
while(!Serial) {}
EEPROM.begin(EEPROM_SIZE);
if(EEPROM.read(powerStateAddress) == LOW || EEPROM.read(powerStateAddress) == HIGH) {
powerState = EEPROM.read(powerStateAddress);
if(powerState == HIGH) {
digitalWrite(relayPin, HIGH);
}
} else {
powerState = LOW;
EEPROM.write(powerStateAddress, powerState);
EEPROM.commit();
}
if(EEPROM.read(groupNumberAddress) != 255) {
groupNumber = EEPROM.read(groupNumberAddress);
}
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(250);
}
Serial.println(WiFi.localIP());
server.on("/controller/setGroup", HTTP_POST, [](AsyncWebServerRequest *request) {}, NULL,
[](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
DynamicJsonDocument doc = parseData(request, data, "/setGroup");
setGroupNumber(doc);
});
server.on("/controller/setColor", HTTP_POST, [](AsyncWebServerRequest *request) {}, NULL,
[](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
DynamicJsonDocument doc = parseData(request, data, "/setColor");
setColorValues(doc);
});
server.begin();
}
void loop() {
Serial.println(powerState);
Serial.println(EEPROM.read(powerStateAddress));
Serial.println(groupNumber);
Serial.println(EEPROM.read(groupNumberAddress));
Serial.print("Brightness: ");
Serial.println(colorSaturation);
Serial.print("green: ");
Serial.println(greenValue);
Serial.print("red: ");
Serial.println(redValue);
Serial.print("blue: ");
Serial.println(blueValue);
Serial.print("white: ");
Serial.println(whiteValue);
Serial.println("---------");
delay(2000);
}
Here is the JSON that I send:
"colorValues": [
255,
255,
255,
255
]
}
This is what the ESP32 receives:
{"colorValues":[255,255,255,255]}33
And this is the result:
green: 255
red: 255
blue: 255
white: 0
Okay here is an example of my JavasScript code when I ran into the issue
var colors = {"red":255, "green":255, "blue":255};
is just added the coma to the back like so
var colors = {"red":255, "green":255, "blue":255,};
and now my arduino can find the blue I intend to use
I ran into the same issue and weird enough if you add an element to the object like the 115:
111,
112,
113,
114,
115
]
}
Then it gets the last 114 and still doesn't get the 115 but atleast you can use you 4 elements, I am guessing it is somethint to do with the last elmenet doesn't have a comma
It's my first time dabbling with socket programming and I stumbled upon this amazing code from https://dzone.com/articles/web-server-c.
WHAT WE NEED TO DO: implement a simple HTTP web server that uses the web browser(input from the user) as a client
Here it is:
/*
* WebServer.c
*
* Created on: Nov 3, 2012
* Author: pavithra
*
* A web server in C language using only the standard libraries.
* The port number is passed as an argument.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#define EOL "\r\n"
#define EOL_SIZE 2
typedef struct {
char *ext;
char *mediatype;
} extn;
//Possible media types
extn extensions[] ={
{"gif", "image/gif" },
{"txt", "text/plain" },
{"jpg", "image/jpg" },
{"jpeg","image/jpeg"},
{"png", "image/png" },
{"ico", "image/ico" },
{"zip", "image/zip" },
{"gz", "image/gz" },
{"tar", "image/tar" },
{"htm", "text/html" },
{"html","text/html" },
{"php", "text/html" },
{"pdf","application/pdf"},
{"zip","application/octet-stream"},
{"rar","application/octet-stream"},
{0,0} };
//find webroot, add design
/*
A helper function
*/
void error(const char *msg) {
perror(msg);
exit(1);
}
/*
A helper function
*/
int get_file_size(int fd) {
struct stat stat_struct;
if (fstat(fd, &stat_struct) == -1)
return (1);
return (int) stat_struct.st_size;
}
/*
A helper function
*/
void send_new(int fd, char *msg) {
int len = strlen(msg);
if (send(fd, msg, len, 0) == -1) {
printf("Error in send\n");
}
}
/*
This function recieves the buffer
until an "End of line(EOL)" byte is recieved
*/
int recv_new(int fd, char *buffer) {
char *p = buffer; // Use of a pointer to the buffer rather than dealing with the buffer directly
int eol_matched = 0; // Use to check whether the recieved byte is matched with the buffer byte or not
while (recv(fd, p, 1, 0) != 0) // Start receiving 1 byte at a time
{
if (*p == EOL[eol_matched]) // if the byte matches with the first eol byte that is '\r'
{
++eol_matched;
if (eol_matched == EOL_SIZE) // if both the bytes matches with the EOL
{
*(p + 1 - EOL_SIZE) = '\0'; // End the string
return (strlen(buffer)); // Return the bytes recieved
}
} else {
eol_matched = 0;
}
p++; // Increment the pointer to receive next byte
}
return (0);
}
/*
A helper function: Returns the
web root location.
*/
char* webroot() {
// open the file "kill.txt" for reading
FILE *in = fopen("kill.txt", "rt");
// read the first line from the file
char buff[1000];
fgets(buff, 1000, in);
// close the stream
fclose(in);
char* nl_ptr = strrchr(buff, '\n');
if (nl_ptr != NULL)
*nl_ptr = '\0';
return strdup(buff);
}
/*
Handles php requests
*/
void php_cgi(char* script_path, int fd) {
send_new(fd, "HTTP/1.1 200 OK\n Server: Web Server in C\n Connection: close\n");
dup2(fd, STDOUT_FILENO);
char script[500];
strcpy(script, "SCRIPT_FILENAME=");
strcat(script, script_path);
putenv("GATEWAY_INTERFACE=CGI/1.1");
putenv(script);
putenv("QUERY_STRING=");
putenv("REQUEST_METHOD=GET");
putenv("REDIRECT_STATUS=true");
putenv("SERVER_PROTOCOL=HTTP/1.1");
putenv("REMOTE_HOST=127.0.0.1");
execl("/usr/bin/php-cgi", "php-cgi", NULL);
}
/*
This function parses the HTTP requests,
arrange resource locations,
check for supported media types,
serves files in a web root,
sends the HTTP error codes.
*/
int connection(int fd) {
char request[500], resource[500], *ptr;
int fd1, length;
if (recv_new(fd, request) == 0) {
printf("Receive Failed\n");
}
printf("%s\n", request);
// Check for a valid browser request
ptr = strstr(request, " HTTP/");
if (ptr == NULL) {
printf("NOT HTTP !\n");
} else {
*ptr = 0;
ptr = NULL;
if (strncmp(request, "GET ", 4) == 0) {
ptr = request + 4;
}
if (ptr == NULL) {
printf("Unknown Request ! \n");
} else {
if (ptr[strlen(ptr) - 1] == '/') {
strcat(ptr, "test.html");
}
strcpy(resource, webroot());
strcat(resource, ptr);
char* s = strchr(ptr, '.');
int i;
for (i = 0; extensions[i].ext != NULL; i++) {
if (strcmp(s + 1, extensions[i].ext) == 0) {
fd1 = open(resource, O_RDONLY, 0);
printf("Opening \"%s\"\n", resource);
if (fd1 == -1) {
printf("404 File not found Error\n");
send_new(fd, "HTTP/1.1 404 Not Found\r\n");
send_new(fd, "Server : Web Server in C\r\n\r\n");
send_new(fd, "<html><head><title>404 Not Found</head></title>");
send_new(fd, "<body><p>404 Not Found: The requested resource could not be found!</p></body></html>\r\n");
//Handling php requests
} else if (strcmp(extensions[i].ext, "php") == 0) {
php_cgi(resource, fd);
sleep(1);
close(fd);
exit(1);
} else {
printf("200 OK, Content-Type: %s\n\n",
extensions[i].mediatype);
send_new(fd, "HTTP/1.1 200 OK\r\n");
send_new(fd, "Server : Web Server in C\r\n\r\n");
if (ptr == request + 4) // if it is a GET request
{
if ((length = get_file_size(fd1)) == -1)
printf("Error in getting size !\n");
size_t total_bytes_sent = 0;
ssize_t bytes_sent;
while (total_bytes_sent < length) {
//Zero copy optimization
if ((bytes_sent = sendfile(fd, fd1, 0,
length - total_bytes_sent)) <= 0) {
if (errno == EINTR || errno == EAGAIN) {
continue;
}
perror("sendfile");
return -1;
}
total_bytes_sent += bytes_sent;
}
//why is it not appearing up to 11:30
}
}
break;
}
int size = sizeof(extensions) / sizeof(extensions[0]);
if (i == size - 2) {
printf("415 Unsupported Media Type\n");
send_new(fd, "HTTP/1.1 415 Unsupported Media Type\r\n");
send_new(fd, "Server : Web Server in C\r\n\r\n");
send_new(fd, "<html><head><title>415 Unsupported Media Type</head></title>");
send_new(fd, "<body><p>415 Unsupported Media Type!</p></body></html>");
}
}
close(fd);
}
}
shutdown(fd, SHUT_RDWR);
}
int main(int argc, char *argv[]) {
int sockfd, newsockfd, portno, pid;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
if (argc < 2) {
fprintf(stderr, "ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd, 5);
clilen = sizeof(cli_addr);
/*
Server runs forever, forking off a separate
process for each connection.
*/
while (1) {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
pid = fork();
if (pid < 0)
error("ERROR on fork");
if (pid == 0) {
close(sockfd);
connection(newsockfd);
exit(0);
} else
close(newsockfd);
} /* end of while */
close(sockfd);
return 0; /* we never get here */
}
NOTE: the kill.txt contains the directory of the server, the files(jpegs, gifs, etc.: /home/user/Desktop)
PROBLEM:
1. After I compile the program and execute it on my web browser as "localhost:port number/file" this is what appears on my web browser:
the image "http://localhost.... cannot be displayed because it contains errors.
And this is what appears on my terminal:
GET /sample5.gif HTTP/1.1
Opening "/home/user/Desktop/sample5.gif"
200 OK, Content-Type: image/gif
GET /favicon.ico HTTP/1.1
Opening "/home/user/Desktop/favicon.ico"
404 File not found Error
How do I fix this? Any help/comment would be greatly appreciated! Thanks.
Where is that favicon.ico bit coming from? /I looked this up and apparently having that favicon.ico bit is quite normal (can somebody please confirm this?)/
… I stumbled upon this amazing code from …
It is indeed amazing how bad it is.
At the end of the function int connection(int fd) there's:
close(fd);
}
}
shutdown(fd, SHUT_RDWR);
}
Browsers don't like the connection being reset by peer (due to close()) before it's tidily shut down. Move the close() after the shutdown().
The program neglects to reap child processes, thus a zombie process remains after each request. #include <signal.h> and add sigignore(SIGCHLD); at the start of main().
If the action for the SIGCHLD signal is set to SIG_IGN, child
processes of the calling processes will not be transformed into zombie
processes when they terminate.
I need to create a c++ console application that query a site in turn to get the html page.
The site is static because when I queried it in the url I see the html file, so I use this code:
send(Socket, "GET /it/ricette/q-torte_forno_statico.html HTTP/1.1\r\nHost: worldrecipes.expo2015.org/\r\nConnection: close\r\n\r\n", strlen("GET /it/ricette/q-torte_forno_statico.html HTTP/1.1\r\nHost: worldrecipes.expo2015.org\r\nConnection: close\r\n\r\n"), 0);
char buffer[1000000];
int nDataLength;
while ((nDataLength = recv(Socket, buffer, 1000000, 0)) > 0) {
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
cout << buffer[i];
i += 1;
}
}
It doesn't give me any errors but don't show me the whole html page and every time that I call send the request I get different answers ... why?
This code below seems to only work on the index page worldrecipes.expo2015.org and not the sub pages. You might want to look at more advanced webbrowser controls for visual studio for parsing and processing HTML.
Like here : http://www.codeproject.com/Articles/3365/Embed-an-HTML-control-in-your-own-window-using-pla
here : https://msdn.microsoft.com/en-us/library/aa752046(v=vs.85).aspx
and here : http://www.codeproject.com/Articles/3919/Using-the-WebBrowser-control-simplified
Example code:
#include <windows.h>
#include <string>
#include <stdio.h>
using std::string;
#pragma comment(lib,"ws2_32.lib")
HINSTANCE hInst;
WSADATA wsaData;
void mParseUrl(char *mUrl, string &serverName, string &filepath, string &filename);
SOCKET connectToServer(char *szServerName, WORD portNum);
int getHeaderLength(char *content);
char *readUrl2(char *szUrl, long &bytesReturnedOut, char **headerOut);
int main()
{
const int bufLen = 1024;
char *szUrl = "http://worldrecipes.expo2015.org/it/ricette/q-torte_forno_statico.html";
long fileSize;
char *memBuffer, *headerBuffer;
FILE *fp;
memBuffer = headerBuffer = NULL;
if ( WSAStartup(0x101, &wsaData) != 0)
return -1;
memBuffer = readUrl2(szUrl, fileSize, &headerBuffer);
printf("returned from readUrl\n");
printf("data returned:\n%s", memBuffer);
if (fileSize != 0)
{
printf("Got some data\n");
fp = fopen("downloaded.file", "wb");
fwrite(memBuffer, 1, fileSize, fp);
fclose(fp);
// SetDlgItemText(hwndDlg, IDC_EDIT4, headerBuffer);
// SetDlgItemText(hwndDlg, IDC_EDIT5, memBuffer);
delete(memBuffer);
delete(headerBuffer);
}
WSACleanup();
return 0;
}
void mParseUrl(char *mUrl, string &serverName, string &filepath, string &filename)
{
string::size_type n;
string url = mUrl;
if (url.substr(0,7) == "http://")
url.erase(0,7);
if (url.substr(0,8) == "https://")
url.erase(0,8);
n = url.find('/');
if (n != string::npos)
{
serverName = url.substr(0,n);
filepath = url.substr(n);
n = filepath.rfind('/');
filename = filepath.substr(n+1);
}
else
{
serverName = url;
filepath = "/";
filename = "";
}
}
SOCKET connectToServer(char *szServerName, WORD portNum)
{
struct hostent *hp;
unsigned int addr;
struct sockaddr_in server;
SOCKET conn;
conn = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (conn == INVALID_SOCKET)
return NULL;
if(inet_addr(szServerName)==INADDR_NONE)
{
hp=gethostbyname(szServerName);
}
else
{
addr=inet_addr(szServerName);
hp=gethostbyaddr((char*)&addr,sizeof(addr),AF_INET);
}
if(hp==NULL)
{
closesocket(conn);
return NULL;
}
server.sin_addr.s_addr=*((unsigned long*)hp->h_addr);
server.sin_family=AF_INET;
server.sin_port=htons(portNum);
if(connect(conn,(struct sockaddr*)&server,sizeof(server)))
{
closesocket(conn);
return NULL;
}
return conn;
}
int getHeaderLength(char *content)
{
const char *srchStr1 = "\r\n\r\n", *srchStr2 = "\n\r\n\r";
char *findPos;
int ofset = -1;
findPos = strstr(content, srchStr1);
if (findPos != NULL)
{
ofset = findPos - content;
ofset += strlen(srchStr1);
}
else
{
findPos = strstr(content, srchStr2);
if (findPos != NULL)
{
ofset = findPos - content;
ofset += strlen(srchStr2);
}
}
return ofset;
}
char *readUrl2(char *szUrl, long &bytesReturnedOut, char **headerOut)
{
const int bufSize = 512;
char readBuffer[bufSize], sendBuffer[bufSize], tmpBuffer[bufSize];
char *tmpResult=NULL, *result;
SOCKET conn;
string server, filepath, filename;
long totalBytesRead, thisReadSize, headerLen;
mParseUrl(szUrl, server, filepath, filename);
///////////// step 1, connect //////////////////////
conn = connectToServer((char*)server.c_str(), 80);
///////////// step 2, send GET request /////////////
sprintf(tmpBuffer, "GET %s HTTP/1.0", filepath.c_str());
strcpy(sendBuffer, tmpBuffer);
strcat(sendBuffer, "\r\n");
sprintf(tmpBuffer, "Host: %s", server.c_str());
strcat(sendBuffer, tmpBuffer);
strcat(sendBuffer, "\r\n");
strcat(sendBuffer, "\r\n");
send(conn, sendBuffer, strlen(sendBuffer), 0);
// SetWindowText(edit3Hwnd, sendBuffer);
printf("Buffer being sent:\n%s", sendBuffer);
///////////// step 3 - get received bytes ////////////////
// Receive until the peer closes the connection
totalBytesRead = 0;
while(1)
{
memset(readBuffer, 0, bufSize);
thisReadSize = recv (conn, readBuffer, bufSize, 0);
if ( thisReadSize <= 0 )
break;
tmpResult = (char*)realloc(tmpResult, thisReadSize+totalBytesRead);
memcpy(tmpResult+totalBytesRead, readBuffer, thisReadSize);
totalBytesRead += thisReadSize;
}
headerLen = getHeaderLength(tmpResult);
long contenLen = totalBytesRead-headerLen;
result = new char[contenLen+1];
memcpy(result, tmpResult+headerLen, contenLen);
result[contenLen] = 0x0;
char *myTmp;
myTmp = new char[headerLen+1];
strncpy(myTmp, tmpResult, headerLen);
myTmp[headerLen] = NULL;
delete(tmpResult);
*headerOut = myTmp;
bytesReturnedOut = contenLen;
closesocket(conn);
return(result);
}
I'm testing a wrapper library for the MySQL C API, and I'm trying to insert a row.
I've tested it in GDB, and the line (in my code) that faults appears as follows:
Breakpoint 1, cq_query (con=0x7fffffffe1c0,
query=0x6014a0 "INSERT INTO TaskType(state,parentID,displayName) VALUES(1,19,'boop')") at cqstatic.c:32
32 return mysql_query(con->con, query);
This query string is formatted correctly (I can paste it into the mysql command line, and it runs fine), so it would appear that something is wrong in the connection (con->con is of type void * cast to MYSQL *).
My other functions which do SELECT and UPDATE work fine. Only insert appears to be broken.
Here is my Test Code
#include <stdio.h>
#include <string.h>
#include <cquel.h>
int main(void)
{
struct dbconn con = cq_new_connection("myurl.tld",
"myuser", "mypasswd", "mydb");
cq_init(1024, 128);
char *fields[] = {
"state",
"parentID",
"displayName"
};
char *vals[] = {
"1",
"19",
"boop"
};
struct drow *row = cq_new_drow(3);
cq_drow_set(row, vals);
struct dlist *list = cq_new_dlist(3, fields, "");
cq_dlist_add(list, row);
cq_insert(con, "TaskType", list);
cq_free_dlist(list);
return 0;
}
Insert Function
int cq_insert(struct dbconn con, const char *table, const struct dlist *list)
{
int rc;
char *query, *columns, *values;
const char *fmt = "INSERT INTO %s(%s) VALUES(%s)";
if (table == NULL)
return 1;
if (list == NULL)
return 2;
query = calloc(CQ_QLEN, sizeof(char));
if (query == NULL)
return -1;
columns = calloc(CQ_QLEN/2, sizeof(char));
if (columns == NULL) {
free(query);
return -2;
}
values = calloc(CQ_QLEN/2, sizeof(char));
if (values == NULL) {
free(query);
free(columns);
return -3;
}
rc = cq_dlist_fields_to_utf8(&con, columns, CQ_QLEN/2, *list);
if (rc) {
free(query);
free(columns);
free(values);
return 100;
}
rc = cq_connect(&con);
if (rc) {
free(query);
free(columns);
free(values);
return 200;
}
for (struct drow *r = list->first; r != NULL; r = r->next) {
rc = cq_drow_to_utf8(&con, values, CQ_QLEN/2, *r);
if (rc)
break;
rc = snprintf(query, CQ_QLEN, fmt, table, columns, values);
if (CQ_QLEN <= (size_t) rc) {
rc = -4;
break;
}
rc = cq_query(&con, query);
if (rc) {
rc = 201;
break;
}
}
cq_close_connection(&con);
free(query);
free(columns);
free(values);
return rc;
}
And one of the important helper functions
int cq_fields_to_utf8(struct dbconn *con, char *buf, size_t buflen,
size_t fieldc, char * const *fieldnames, bool usequotes)
{
int rc = 0;
size_t num_left = fieldc, written = 0;
if (num_left == 0)
return 1;
char *temp = calloc(CQ_FMAXLEN+3, sizeof(char));
if (NULL == temp)
return -1;
char *field = calloc((CQ_FMAXLEN+3)*2+1, sizeof(char));
if (NULL == field) {
free(temp);
return -2;
}
/* prevent appending to buffer */
buf[0] = '\0';
cq_connect(con);
for (size_t i = 0; i < fieldc; ++i) {
bool escaped = fieldnames[i][0] == '\\';
const char *orig = escaped ? &fieldnames[i][1] : fieldnames[i];
const char *value;
bool isstr = false;
if (!escaped) {
mysql_real_escape_string(con->con, field, orig, strlen(orig));
value = field;
if (usequotes)
for (size_t j = 0; j < strlen(value); ++j) {
if (!isdigit(value[j])) {
isstr = true;
break;
}
}
} else {
value = orig;
}
const char *a = isstr ? "'" : "";
const char *c = --num_left > 0 ? "," : "";
written += snprintf(temp, CQ_FMAXLEN+3, "%s%s%s%s", a, value, a, c);
if (written >= buflen) {
rc = 2;
break;
}
strcat(buf, temp);
}
cq_close_connection(con);
free(field);
free(temp);
return rc;
}
used when setting up the query string.
Found my own issue. Blame the 10 minute rule.
I didn't look closely enough at cq_insert(), and it is making a double connection, closing the second one, leaving the first one lost, and the pointer pointing to freed memory, so segfault.