Parse gets error in check50 pset6 - cs50

I've coded the parse function for this pset but check50 only checks as valid the following:
:) server.c exists
:) server compiles
:( HTTP/1.0 returns error code 505
\ expected output, but not "HTTP/1.1 400 Bad Request\r\nContent-Typ..."
:( Method of 'abcGET' returns error code 405
\ expected output, but not "HTTP/1.1 400 Bad Request\r\nContent-Typ..."
:( Method of 'GETabc' returns error code 405
\ expected output, but not "HTTP/1.1 400 Bad Request\r\nContent-Typ..."
:( request-target without starting '/' returns error code 501
\ expected output, but not "HTTP/1.1 400 Bad Request\r\nContent-Typ..."
:( request-target of abc/hello.php returns error code 501
\ expected output, but not "HTTP/1.1 400 Bad Request\r\nContent-Typ..."
:( Requesting cat.exe returns error code 501
\ expected output, but not "HTTP/1.1 400 Bad Request\r\nContent-Typ..."
:( Requesting non-existant file returns error code 404
\ expected output, but not "HTTP/1.1 400 Bad Request\r\nContent-Typ..."
:) Requesting request-target with " returns error code 400
:) Two spaces after GET returns error code
:) A space within the request target returns error code
:) Two spaces before HTTP/1.1 returns error code
So basically only the checking of the spaces is working. I would like to have some guidance of where the problem is in my code when comparing strings. I guess there's something wrong with the use of the functions but after researching for hours I still don't see a solution. I'm a total beginner and I would really appreciate some help. Thanks
This is the code for my parse function
bool parse(const char* line, char* abs_path, char* query)
{
// TODO
// Get the lenght of line
int l = strlen(line);
// Store the place in the string
int a = 0;
// Stores number of total spaces
int spaces = 0;
// Iterate in line
for (int i = 0; i < l; i++)
{// Look for spaces
if (isspace(line[i]) == 0)
{
spaces++;
}
}
// If there are more than the 2 required spaces
if (spaces > 2)
{
error(400);
printf("400 Bad Request\n");
return false;
}
// If request - target doen't begin with "/"
// Look for the fist space
for (int i = 0; i < l; i++)
{// Look for space
if (isspace(line[i]) == 0)
{
a = i + 1;
break;
}
}
if (line[a] != '/')
{
error(501);
printf("501 not implemented\n");
return false;
}
{
error(405);
printf("405 Method Not Allowed\n");
return false;
}
// If request-target contains "
// Will store position of second space
int b = 0;
// Look for the second space
for (int i = a; i < l; i++)
{
if (isspace(line[i]) == 0)
{
b = i;
break;
}
}
// Find if there is a " in request-target
for (int i = a; i < b; i++)
{
if ( line[i] == '"')
{
error(400);
printf("400 Bad Request\n");
return false;
}
}
// If HTTP version isn't HTTP/1.1
char http[7] = "";
for (int i = b + 1; i < (b + 1) + 7/*Chars
from the second space till the end of HTTP/1.1*/;i++)
{
http[i] = line[i];
}
if (strcmp(http, "HTTP/1.1") != 0)
{
error(505);
printf("505 HTTP Version Not Supported\n");
return false;
}
// Store absolute-path at the address in abs_path and the query string at query
// Separate the query
// String to store the query
char query2[8190 + 1] = "";
// Store the position in line where the query string starts
int c = 0;
// Counter for query array
int q = 0;
for (int i = b - 1/*before the space after the query*/; i > a/*after the first space*/;i--)
{
if (line[i] == '=')
{
c = i - 1;
break;
}
}
// Pass the string to query2
for (int i = c; i < (b - 1); i++)
{
query2[q] = line[i];
q++;
}
// If there is no query, make query2 empty
if (query2[0] != 'q')
{
strcpy(query2, "");
}
// Allocate query2 and query at the heap
query = malloc(sizeof(query2));
// Copy query2 to query
strcpy(query, query2);
// Separate absolute path
// Declare char array to store absolute path
char abs1[8190 + 1] = "";
// Make space at the heap
abs_path = malloc(sizeof(abs1));
for (int i = a /*where the / after the first space starts*/; i < (c - 1);
i++)
{
abs1[i] = line[i];
}
// Copy abs to abs_path
strcpy(abs_path, abs1);
return true;
}

Parse is always returning "400 Bad Request", that indicates that the condition:
if (spaces > 2)
is always evaluting to true, that is because line has two or more spaces BUT that is because the format for an http request requires that a space separete the method from the request and another space to separe the request from the http-version.
You need to search for two consequtive spaces, not two spaces in the whole line.
And you should use the recomended functions instead of a lot of for loops.

Related

Check50 Errros: Not passing " handles most basic words properly" and "handles substrings properly" tests. Check50 also can't check for a memory error

I am working on Pset5 Speller. I've managed to get all my errors down to three, but I cannot figure out how to fix my program so that it handles most basic words and handles substrings. I have run debugger, but it doesn't really help. I have also run valgrind and it says that no memory leaks are possible. I think the problem maybe my check function or hash function, so I have changed them a few times but I still get the same check50 results. The sumbit50 link:
https://submit.cs50.io/check50/57b8af186bcdadea0b585f0785ef47a5cf317b99 says that check50 only ever finds 1 word in the dictionary and identifies all words as misspelled. I really am not quite sure what the problem is. Can someone help me please? Here are my checks and hash functions. Thank you!!!
// Hashes word to a number
unsigned int hash(const char *word)
{
// hash function created by Deliberate Think on Youtube
int hash_key = 0;
int n;
for (int i = 0; word[i] != '\0'; i++)
{
if (isalpha(word[i]))
{
n = word[i] - 'a' + 1;
}
else
{
n = 27;
}
hash_key = ((hash_key << 3) + n) % N;
}
return hash_key;
}
// Returns true if word is in dictionary else false
bool check(const char *word)
{
// create an array to store words, then copy words from table to compare
int n = strlen(word);
char wordcheck[LENGTH + 1];
strcpy(wordcheck, word);
for (int i = 0; i < n; i++)
{
wordcheck[i] = tolower(word[i]);
}
//hashes word, then accesses linked list at that value
int j = hash(wordcheck);
node *cursor = hashtable[j];
if (hashtable[j] != NULL)
{
//iterates through linked list: cursor pointer starts at head of list and while there is a value, it moves on to the next word in the list
while (cursor != NULL)
{
//if the word is found, return true
if (strcmp(cursor->word, wordcheck) == 0)
{
return true;
}
else
{
cursor = cursor->next;
}
}
}
return false;
}
bool load(const char *dictionary)
{
//opens dictionary file
FILE *inputfile = fopen(dictionary, "r");
if (inputfile == NULL)
{
return false;
}
//initializes new node pointer and reads words from new file while !EOF
char word[LENGTH + 1];
while (fscanf(inputfile, "%s", word) != EOF)
{
//actually creates and initializes new node( creates space in memory for node using malloc function) and copies word into node while keeping tracking of # of words
node *new_node = malloc(sizeof(node));
if (new_node == NULL)
{
unload();
return false;
}
else
{
strcpy(new_node->word, word);
}
//hashes words in node to determine which linked list to use
int j = hash(new_node->word);
//initializes node pointer to first bucket in hashtable
node *head = hashtable[j];
if (head == NULL)
{
//if there is no data in linked list, new_node becomes head of linked list
hashtable[j] = new_node;
}
else
{
//if data exists, node points to next word in list, then head of linked list points to node pointer
new_node->next = hashtable[j];
hashtable[j] = new_node;
}
wordcount++;
fclose(inputfile);
}
return true;
}
I solved it! I had to change the way the hash function was written inside of the load function and rewrite fclose(inputfile) to be outside of one of the curly braces. All errors gone!

Arduino: Parsing not showing the list of string parsed

i am trying to parse a list of messages that is converted to a single line of string with a delimiter of '*' for each sms, now whenever i pass only 1 sms it prints the desired output, but when i pass more than 1 sms it will not parse or split each message from the converted single line of string
this is what the converted single line of string looks like
+CMGL: 14,REC UNREAD,+639321576684,Ralph Manzano,16/05/04,02:27:03+32,You$*+CMGL: 15,REC UNREAD,+639321576684,Ralph Manzano,16/05/04,02:27:08+32,There$*+CMGL: 16,REC UNREAD,+639321576684,Ralph Manzano,16/05/04,02:26:59+32,Hey$*+CMGL: 17,REC UNREAD,+639321576684,Ralph Manzano,16/05/04,02:35:31+32,Hi$*>
this is actually a response of an AT command but as you can see each sms is divided by '*' and has an '>' as and indicator of an end of the line. this is the code that i use to parse this converted single line of string.
void parse_list(String list) {
Serial.println("Parsing...");
delay(1000);
String sms1 = "";
String sms2 = "";
String sms3 = "";
String sms4 = "";
char charData, charData2;
int index = 0, index2 = 0;
for (int i = 0; i < list.length(); i++) {
charData = list.charAt(i);
if (charData == '*') {
index++;
}
else if (charData == '>') {
index = 0;
}
else {
SMSlist[index] += charData;
}
}
sms1 = SMSlist[0];
sms2 = SMSlist[1];
sms3 = SMSlist[2];
sms4 = SMSlist[3];
Serial.println(sms1);
delay(1000);
Serial.println(sms2);
delay(1000);
Serial.println(sms3);
delay(1000);
Serial.println(sms4);
delay(1000);
clear_smslist();
}
void clear_smslist() {
for (int i = 0; i < 10; i++) {
SMSlist[i] = "";
}
}
what seems to be wrong in my code? thank a lot for the help

Iterate through characters in a String in Swift

I want to iterate through a String with condition to skip 2 or more characters in 1 iteration. An example code in C++
// str = "123"
for (int i = 0; i < str.size(), i++) {
if (str[i] == '2') {
// do something
i++;
}
// do something
}
My Swift version is like this, but after the iteration finishs, there is an error saying:
"fatal error: Can't form a Character from an empty String"
// str = "123"
for var index = str.startIndex; index != str.endIndex; index = index.advancedBy(1) {
if (str[index] == "2") {
// do something
index = index.advancedBy(1)
}
// do something
}
I guess this is the place I got wrong, "index != str.endIndex"
How to fix it or any alternative way to achieve this?

CString : Find string contains all whitespaces

I am trying to come up with a function that will look to see whether the given CString contains all white spaces.
The one i came up with below doesn't seem to work. Any suggestions?
BOOL IsAllWhiteSpace(CString str)
{
for (int i = 0; i < str.GetLength(); i++)
{
char letter = str.GetAt(i);
if (letter != ' ')
{
return FALSE;
}
}
return TRUE;
}
You should explain what does it mean - "doesn't seem to work"
its wrong for empty string, and also it also does not include all white-space characters : (0x09 – 0x0D or 0x20). Below is a fixed version:
BOOL IsAllWhiteSpace(const CString& str)
{
if (str.IsEmpty())
return FALSE;
for (int i = 0; i < str.GetLength(); i++)
{
char letter = str.GetAt(i);
if (!_istspace(letter))
{
return FALSE;
}
}
return TRUE;
}
You can rewrite your function in one line:
return str.TrimLeft().IsEmpty();

PEGjs: Fallback (backtrack?) to string if floating point rule fail

I have an atom rule that tries to parse everything as either a number or a quoted string first, if that fails, then treat the thing as a string.
Everything parses fine except one particular case that is this very specific string:
DUD 123abc
Which fails to parse with Expected " ", "." or [0-9] but "a" found. error.
What I expect: it should parse successfully and return string "123abc" as a string atom. You can see several of my unsuccessful attempts commented out in the grammar content below.
Any help/tips/pointers/suggestions appreciated!
You can try the grammar on the online PEG.js version. I'm using node v0.8.23 and pegjs 0.7.0
Numbers that parses correctly:
`123
`0
`0.
`1.
`.23
`0.23
`1.23
`0.000
. <--- as string, not number and not error
I want 123abc to be parsed as a string, is this possible?
This is my entire grammar file:
start = lines:line+ { return lines; }
// --------------------- LINE STRUCTURE
line = command:command eol { return command; }
command = action:atom args:(sep atom)*
{
var i = 0, len = 0;
for (var i = 0, len = args.length; i < len; i++) {
// discard parsed separator tokens
args[i] = args[i][1];
}
return [action, args];
}
sep = ' '+
eol = "\r" / "\n" / "\r\n"
atom = num:number { return num; }
/ str:string_quoted { return str; }
/ str:string { return str; }
// --------------------- COMMANDS
// TODO:
// --------------------- STRINGS
string = chars:([^" \r\n]+) { return chars.join(''); }
string_quoted = '"' chars:quoted_chars* '"' { return chars.join(''); }
quoted_chars = '\\"' { return '"'; }
/ char:[^"\r\n] { return char; }
// --------------------- NUMBERS
number = integral:('0' / [1-9][0-9]*) fraction:("." [0-9]*)?
{
if (fraction && fraction.length) {
fraction = fraction[0] + fraction[1].join('');
} else {
fraction = '';
}
integral = integral instanceof Array ?
integral[0] + integral[1].join('') :
'0';
return parseFloat(integral + fraction);
}
/ ("." / "0.") fraction:[0-9]+
{
return parseFloat("0." + fraction.join(''));
}
/*
float = integral:integer? fraction:fraction { return integral + fraction; }
fraction = '.' digits:[0-9]* { return parseFloat('0.' + digits.join('')); }
integer = digits:('0' / [1-9][0-9]*)
{
if (digits === '0') return 0;
return parseInt(digits[0] + digits[1].join(''), 10);
}
*/
Solved this by adding !([0-9\.]+[^0-9\.]) which is sort of a look-ahead infront of the number rule.
I know that the atom rule will match so what it effectively does is making the number rule fails a bit sooner. Hopefully this can helps someone with ambiguous cases in the future.
So the number rule now becomes:
number = !([0-9\.]+[^0-9\.]) integral:('0' / [1-9][0-9]*) fraction:("." [0-9]*)?
I think that checking that the character trailing number is a number-separator (not an alphanum) would have also worked, and more cheaply.
number = integral:('0' / [1-9][0-9]*) fraction:("." [0-9]*)? !([0-9A-Za-z])

Resources