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
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!
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
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?
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();
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])