Lexical analyzer, Compare two different lines of a text file - visual-c++

I have to use a lexical analyzer to compare 2 lines of a text file, if the 2 lines are identical I merge them this way:
STATE a TO a b b b OUT 0 1 1 0
STATE b TO a b b b OUT 0 1 1 0
STATE ab TO a b b b OUT 0 1 1 0
Current_State = a
Next_States = a b b b
Outputs = 0 1 1 0
I've ignored in the text file everything that comes before the state,
my code is as follows :
#pragma warning(disable:4786)
#include <string>
#include <map>
#include <vector>
#include <iostream>
#include <stdio.h>
using namespace std;
#define Getc(s) getc(s)
#define Ungetc(c) {ungetc(c,IP_Input); ugetflag=1;}
typedef vector<string> list; // Um Eingänge ausgänge zu speichern
list next_states;
list Outputs;
int tok = 0;
/*
* Lexical analyzer states.
*/
enum parcases { // Case that can occur C_.....
c_SkipBegin, // When State is found go to DEFCURRENTSTATE
c_DEFCURRENTSTATE, // DEFCURRENTSTATE occurs scan the states
c_DEFNEXTSTATES, // DEFNEXTSTATES occurs scan the next states
c_DEFOUT, //DEFOUT occurs scan the outputs
c_FINISHED
};
enum lexstate {
L_START, L_INT, L_IDENT, L_STRING, L_STRING2,
L_COMMENT, L_TEXT_COMMENT, L_LINE_COMMENT, L_END_TEXT_COMMENT
};
const int STRING1 = 3;
const int IDENTIFIER = 4;
const int INTEGER1 = 5;
const int TOKENSTART = 300;
class CParser
{
public:
string yytext; //input buffer
struct tyylval { //value return structure
string s; //string
int i; //integer
}yylval;
FILE* IP_Input; //Input File
FILE* IP_Error; //Error Output
FILE* IP_List; //List Output
int IP_LineNumber; //Line counter
int ugetflag; //checks ungets
int prflag; //controls printing
map<string, int> IP_Token_table; //Tokendefinitions
map<int, string> IP_revToken_table; //reverse Tokendefinitions
string current_states; // Vector um scanned_states zu speichern
list first_lines;
list next_states; // Vector um scanned_inputs zu speichern
list Outputs; // Vector um scanned_outputs zu speichern
int yylex(); //lexical analyser
void yyerror(char* ers); //error reporter
int IP_MatchToken(string& tok); //checks the token
void InitParse(FILE* inp, FILE* err, FILE* lst); //Sets the File pointers
int yyparse(); //parser
list fusion_lines(list& list_one, list& list_two);
bool compare(list& list_one, list& list_two);
void pr_tokentable(); //test output for tokens
void IP_init_token_table(); //loads the tokens
void Load_tokenentry(string str, int index); //load one token
void PushString(char c); //Used for dtring assembly
parcases SkipTillBegin(int tok, list& first_lines);// Skip till begin is found
parcases ScanTheCurrentState(int tok, string& current_states); // Scan the STATE
parcases ScanTheNextStates(int tok, list& next_states); // Scan the TO STATE
parcases ScanTheOutputs(int tok, list& Outputs); // Scan the Outputs
CParser() { IP_LineNumber = 1; ugetflag = 0; prflag = 0; }; //Constructor
};
//------------------------------------------------------------------------
// Adds a character to the string value
void CParser::PushString(char c)
{
yylval.s += c;
}
//------------------------------------------------------------------------
void CParser::Load_tokenentry(string str, int index)
{
IP_Token_table[str] = index;
IP_revToken_table[index] = str;
}
void CParser::IP_init_token_table()
{
Load_tokenentry("STRING1", 3);
Load_tokenentry("IDENTIFIER", 4);
Load_tokenentry("INTEGER1", 5);
int ii = TOKENSTART;
Load_tokenentry("AND", ii++);
Load_tokenentry("OR", ii++);
Load_tokenentry("Begin", ii++);
Load_tokenentry("End", ii++);
}
//------------------------------------------------------------------------
void CParser::pr_tokentable()
{
typedef map<string, int>::const_iterator CI;
const char* buf;
printf("Symbol Table ---------------------------------------------\n");
for (CI p = IP_Token_table.begin(); p != IP_Token_table.end(); ++p) {
buf = p->first.c_str();
printf(" key:%s val:%d\n ", buf, p->second);
}
}
int CParser::yyparse()
{
string Current_state;
list given_first_lines;
list given_Next_states;
list given_outputs;
// Define the first state first we read the file till begin Occur what is befor "State" is ignored.
parcases Case = c_SkipBegin;
printf(" %s ", first_lines, "/ln");
while ((tok = yylex()) != IP_Token_table["End"])
{
if (Case == c_SkipBegin)
{
Case = SkipTillBegin(tok, first_lines);
}
else if (Case == c_DEFCURRENTSTATE)
{
}
}
return 0;
}
//------------------------------------------------------------------------
parcases CParser::SkipTillBegin(int tok, list& first_lines)
{
parcases retval;
if (tok != IP_Token_table["STATE"])
{
first_lines.push_back(string(yylval.s)); // the 2 IN lines
retval = c_SkipBegin;
}
else {
retval = c_DEFCURRENTSTATE;
}
return retval;
}
parcases CParser::ScanTheCurrentState(int tok, string& current_state)
{
parcases retval = c_DEFCURRENTSTATE;
if (tok == IDENTIFIER) //IDENTIFIER = a
{
current_state = string(yylval.s); // a,b,c
retval = c_DEFCURRENTSTATE;
}
else if (tok == 'TO') { // State is done
retval = c_DEFNEXTSTATES;
}
return retval;
}
parcases CParser::ScanTheNextStates(int tok, list& next_states)
{
parcases retval = c_DEFNEXTSTATES;
if (tok == IDENTIFIER) //IDENTIFIER = a
{
next_states.push_back(string(yylval.s)); //a, b,x
retval = c_DEFNEXTSTATES;
}
else if (tok == 'OUT') { // States are done
retval = c_DEFOUT;
}
return retval;
}
parcases CParser::ScanTheOutputs(int tok, list& Outputs)
{
parcases retval = c_DEFOUT;
if ((tok == INTEGER1) || (tok == IDENTIFIER)) //IDENTIFIER = 1,0,x
{
Outputs.push_back(string(yylval.s)); //1,0,x
retval = c_DEFOUT;
}
else if (tok == '\n') { // Outputs are done
retval = c_FINISHED;
}
return retval;
}
bool CParser::compare(list& list_one, list& list_two)
{
bool match = false;
if (list_one == list_two)
{
match = true;
//list_two = 0;
}
return match;
}
list CParser::fusion_lines(list& list_one, list& list_two)
{
}
//------------------------------------------------------------------------
/*
* Parse File:
*
*/
void CParser::InitParse(FILE* inp, FILE* err, FILE* lst)
{
/*
* Set up the file state to something useful.
*/
IP_Input = inp;
IP_Error = err;
IP_List = lst;
IP_LineNumber = 1;
ugetflag = 0;
/*
* Define both the enabled token and keyword strings.
*/
IP_init_token_table();
}
//------------------------------------------------------------------------
int CParser::IP_MatchToken(string& tok)
{
int retval;
if (IP_Token_table.find(tok) != IP_Token_table.end()) {
retval = (IP_Token_table[tok]);
}
else {
retval = (0);
}
return retval;
}
//------------------------------------------------------------------------
/*
* yylex:
*
*/
int CParser::yylex()
{
//Locals
int c;
lexstate s;
/*
* Keep on sucking up characters until we find something which
* explicitly forces us out of this function.
*/
for (s = L_START, yytext = ""; 1;) {
c = Getc(IP_Input);
yytext = yytext + (char)c;
if (!ugetflag) {
if (c != EOF)if (prflag)fprintf(IP_List, "%c", c);
}
else ugetflag = 0;
switch (s) {
//Starting state, look for something resembling a token.
case L_START:
if (isdigit(c)) {
s = L_INT;
}
else if (isalpha(c) || c == '\\') {
s = L_IDENT;
}
else if (isspace(c)) {
if (c == '\n') {
IP_LineNumber += 1;
if (prflag)
fprintf(IP_List, "%5d ", (int)IP_LineNumber);
}
yytext = "";
}
else if (c == '/') {
yytext = "";
s = L_COMMENT;
}
else if (c == '"') {
s = L_STRING;
}
else if (c == EOF) {
return ('\0');
}
else {
return (c);
}
break;
case L_COMMENT:
if (c == '/')
s = L_LINE_COMMENT;
else if (c == '*')
s = L_TEXT_COMMENT;
else {
Ungetc(c);
return('/'); /* its the division operator not a comment */
}
break;
case L_LINE_COMMENT:
if (c == '\n') {
s = L_START;
Ungetc(c);
}
yytext = "";
break;
case L_TEXT_COMMENT:
if (c == '\n') {
IP_LineNumber += 1;
}
else if (c == '*')
s = L_END_TEXT_COMMENT;
yytext = "";
break;
case L_END_TEXT_COMMENT:
if (c == '/') {
s = L_START;
}
else {
s = L_TEXT_COMMENT;
}
yytext = "";
break;
/*
* Suck up the integer digits.
*/
case L_INT:
if (isdigit(c)) {
break;
}
else {
Ungetc(c);
yylval.s = yytext.substr(0, yytext.size() - 1);
yylval.i = atoi(yylval.s.c_str());
return (INTEGER1);
}
break;
/*
* Grab an identifier, see if the current context enables
* it with a specific token value.
*/
case L_IDENT:
if (isalpha(c) || isdigit(c) || c == '_')
break;
Ungetc(c);
yytext = yytext.substr(0, yytext.size() - 1);
yylval.s = yytext;
if (c = IP_MatchToken(yytext)) {
return (c);
}
else {
return (IDENTIFIER);
}
/*
* Suck up string characters but once resolved they should
* be deposited in the string bucket because they can be
* arbitrarily long.
*/
case L_STRING2:
s = L_STRING;
if (c == '"') {
PushString((char)c);
}
else {
if (c == '\\') {
PushString((char)c);
}
else {
PushString((char)'\\');
PushString((char)c);
}
}
break;
case L_STRING:
if (c == '\n')
IP_LineNumber += 1;
else if (c == '\r')
;
else if (c == '"' || c == EOF) {
return (STRING1);
}
else if (c == '\\') {
s = L_STRING2;
}
else
PushString((char)c);
break;
default: printf("***Fatal Error*** Wrong case label in yylex\n");
}
}
}
//------------------------------------------------------------------------
int main(int argc, char* argv[])
{
FILE* inf;
CParser obj;
//char fistr[100];
string fistr;
printf("Enter filename:\n");
//gets(fistr);
cin >> fistr;
inf = fopen(fistr.c_str(), "r");
if (inf == NULL) {
printf("Cannot open input file %s\n", fistr);
return 0;
}
CParser obj;
obj.InitParse(inf, stderr, stdout);
// obj.pr_tokentable();
obj.yyparse();
return 0;
//system("pause");
}
I wrote this classes to put the current state, the next states and the output in a vector
parcases CParser::SkipTillBegin(int tok, list& first_lines)
parcases CParser::ScanTheCurrentState(int tok, string& current_state)
parcases CParser::ScanTheNextStates(int tok, list& next_states)
parcases CParser::ScanTheOutputs(int tok, list& Outputs)
this class is the lexical analyzer it differentiates the integers of identifiers and strings
int CParser::yylex()
The other classes aren't really important to understand.
I wrote this class to compare
bool CParser::compare(list& list_one, list& list_two)
{
bool match = false;
if (list_one == list_two)
{
match = true;
//list_two = 0;
}
return match;
}
and I started this one to merge two lines together
list CParser::fusion_lines(list& list_one, list& list_two) but i am stuck here and on the output class int CParser::yyparse()
I couldn't find a way to do it correctly and to compare two different lines of the text file with the lexical analyzer.

Related

PSET5 (Speller) Valgrind Error: Valgrind tests failed

I failed to pass the Valgrind tests and couldn't figure out what went wrong with my code. It seems like the issue is in the load() function as the Valgrind tests pointed out at the malloc() line. Could anyone help me take a look? Any guidance would be appreciated. Thank you!
Here is my code:
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// TODO: Choose number of buckets in hash table
const unsigned int N = 100;
// Hash table
node *table[N];
int count =0;
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
// TODO
int i = hash(word);
node *cursor = table[i];
if (table[i] == NULL)
{
return false;
}
else
{
while(cursor!= NULL)
{
if(strcasecmp(cursor->word, word) == 0)
{
return true;
}
else
{
cursor = cursor->next;
}
}
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
// TODO: Improve this hash function
int bucket;
if(word[1] != 0)
{
bucket = (((toupper(word[0])-'A') * (toupper(word[1]- 'A')))% 10 + (toupper(word[0])-'A'));
}
else
{
bucket = (((toupper(word[0])-'A') * (toupper(word[0])-'A'))%10 + (toupper(word[0])-'A'));
}
return bucket;
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
// TODO 1
//open the dictionary
FILE *file = fopen(dictionary, "r");
if(file == NULL)
{
printf("Can't load the dictionary\n");
return false;
}
//read string from file one at a time
char word[LENGTH + 1];
for (int i=0; i < N; i++)
{
table[i] = NULL;
}
while(fscanf(file, "%s", word) != EOF)
{
node *n = malloc(sizeof(node));
//create a new node for each word
if(n == NULL)
{
unload();
return false;
}
strcpy(n->word, word);
n->next = NULL;
count++;
char *c = n->word;
int number = hash(c);
if (table[number] != NULL)
{
//point the new node to the first node existing in the table
n->next = table[number];
//point the header to the new node
table[number] = n;
}
else
{
//n->next = NULL;
table[number] = n;
}
}
fclose(file);
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
// TODO
return count;
//return 0;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
for (int i = 0; i > N; i++)
{
node *cursor = table[i];
while(cursor != NULL)
{
node *tmp = cursor;
cursor = cursor->next;
free(tmp);
}
free(cursor);
}
// TODO
return true;
}
Here is what the Valgrind tests show:
Valgrind tests
c.99 is this line -> node *n = malloc(sizeof(node));
The problem is in unload. It doesn't free any nodes. Review this line carefully and critically, it contains the error.
for (int i = 0; i > N; i++)

CS50 speller pset 5 (accessed 1 byte that does not belong to me but can't find the byte)

After running my code through help50 Valgrind, I got the following error message:
==6830== Invalid read of size 1
==6830== at 0x4C33614: strcasecmp (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6830== by 0x401176: check (dictionary.c:52)
==6830== by 0x400CD9: main (speller.c:112)
Looks like you're trying to access 1 byte of memory that isn't yours? Did you try to index into an array beyond its bounds? Take a closer look at line 52 of dictionary.c.
I think it has something to do with my check function but line 52 is just an if statement and I can't figure out where I'm trying to access that 1 byte from.**
My code is below:
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <strings.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table
const unsigned int N = 1000;
//Number of words
unsigned int noWords = 0;
//Variable to check if dictionary loaded
bool isLoaded = false;
// Hash table
node *table[N];
// Returns true if word is in dictionary else false
bool check(const char *word)
{
//Changing letters to lower case because case insensitive
//Copy created because word argument is a constant. copy can be edited
int n = strlen(word) + 1;
char copy[LENGTH + 1];
for (int i = 0; i < n; i++)
{
copy[i] = tolower(word[i]);
}
// Add null terminator to end string
copy[n] = '\0';
//Hash the word to convert it to index and check if it's in any of the linked lists
int index = hash(copy);
if (table[index] != NULL) //Check if word is in linked list
{
for (node *cursor = table[index]; cursor != NULL; cursor = cursor -> next)
{
if (strcasecmp(cursor -> word, copy) == 0)
{
return true;
}
}
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
//Taken from http://www.cse.yorku.ca/~oz/hash.html (by djb2)
unsigned long h = 5381;
int c;
while ((c = *word++))
{
c = tolower(c);
h = (((h << 5) + h) + c) % N; /* hash * 33 + c*/
}
return h;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
char word[LENGTH + 1];
//Open dictionary
FILE *f = fopen(dictionary, "r");
//Check if file can be opened
if (f == NULL)
{
printf("%s\n", "File cannot be opened!");
return false;
}
//Read strings from file
while (fscanf(f, "%s", word) != EOF)
{
noWords++;
node *newNodePointer = malloc(sizeof(node));
if (newNodePointer == NULL)
{
unload();
printf("Out of memory");
return false;
}
int index = hash(word);//hashtable is an array of linked list. index helps insert node into hashtable
strcpy(newNodePointer -> word, word);//Copies word from infile into new node's word field
if (table[index] == NULL)//Check if same word already exists in the bucket
{
newNodePointer -> next = NULL;
table[index] = newNodePointer;
}
else
{
newNodePointer -> next = table[index];
table[index] = newNodePointer;
}
free(newNodePointer);
}
fclose(f);
isLoaded = true;
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
if (isLoaded)
{
return noWords;
}
return 0;
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
//Check if there's even a loaded dictionary
if (!isLoaded)
{
return false;
}
//Iterate through hashtable
for (int i = 0; i < N; i++)
{
if (table[i] != NULL)
{
node *cursor = table[i];
while (cursor != NULL)
{
node *tmp = table[i]; //tmp pointer continues pointing at table[i] while cursor points at next item in hashtable
cursor = cursor -> next;
free(tmp);
}
}
}
return true;
}
The problem is from here in load: free(newNodePointer);. It just released the memory where the word and the next pointer are stored!

Find the word in the stream?

Given an infinite stream of characters and a list L of strings, create a function that calls an external API when a word in L is recognized during the processing of the stream.
Example:
L = ["ok","test","one","try","trying"]
stream = a,b,c,o,k,d,e,f,t,r,y,i,n,g.............
The call to external API will happen when 'k' is encountered, again when the 'y' is encountered, and again at 'g'.
My idea:
Create trie out of the list and navigate the nodes as you read from stream in linear time. But there would be a bug if you just do simple trie search.
Assume you have words "abxyz" and "xyw" and your input is "abxyw".In this case you can't recognize "xyw" with trie.
So search should be modified as below:
let's take above use case "abxyw". We start the search and we find we have all the element till 'x'. Moment you get 'x' you have two options:
Check if the current element is equal to the head of trie and if it is equal to head of trie then call recursive search.
Continue till the end of current word. In this case for your given input it will return false but for the recursive search we started in point 1, it will return true.
Below is my modified search but I think it has bugs and can be improved. Any suggestions?
#define SIZE 26
struct tri{
int complete;
struct tri *child[SIZE];
};
void insert(char *c, struct tri **t)
{
struct tri *current = *t;
while(*c != '\0')
{
int i;
int letter = *c - 'a';
if(current->child[letter] == NULL) {
current->child[letter] = malloc(sizeof(*current));
memset(current->child[letter], 0, sizeof(struct tri));
}
current = current->child[letter];
c++;
}
current->complete = 1;
}
struct tri *t;
int flag = 0;
int found(char *c, struct tri *tt)
{
struct tri *current = tt;
if (current == NULL)
return 0;
while(*c != '\0')
{
int i;
int letter = *c - 'a';
/* if this is the first char then recurse from begining*/
if (t->child[letter] != NULL)
flag = found(c+1, t->child[letter]);
if (flag == 1)
return 1;
if(!flag && current->child[letter] == NULL) {
return 0;
}
current = current->child[letter];
c++;
}
return current->complete;
}
int main()
{
int i;
t = malloc(sizeof(*t));
t->complete = 0;
memset(t, 0, sizeof(struct tri));
insert("weathez", &t);
insert("eather", &t);
insert("weather", &t);
(1 ==found("weather", t))?printf("found\n"):printf("not found\n");
return 0;
}
What you want to do is exactly what Aho-Corasick algorithm does.
You can take a look at my Aho-Corasick implementation. It's contest-oriented, so maybe not focused on readability but I think it's quite clear:
typedef vector<int> VI;
struct Node {
int size;
Node *fail, *output;
VI id;
map<char, Node*> next;
};
typedef pair<Node*, Node*> P;
typedef map<char, Node*> MCP;
Node* root;
inline void init() {
root = new Node;
root->size = 0;
root->output = root->fail = NULL;
}
Node* add(string& s, int u, int c = 0, Node* p = root) {
if (p == NULL) {
p = new Node;
p->size = c;
p->fail = p->output = NULL;
}
if (c == s.size()) p->id.push_back(u);
else {
if (not p->next.count(s[c])) p->next[s[c]] = NULL;
p->next[s[c]] = add(s, u, c + 1, p->next[s[c]]);
}
return p;
}
void fill_fail_output() {
queue<pair<char, P> > Q;
for (MCP::iterator it=root->next.begin();
it!=root->next.end();++it)
Q.push(pair<char, P> (it->first, P(root, it->second)));
while (not Q.empty()) {
Node *pare = Q.front().second.first;
Node *fill = Q.front().second.second;
char c = Q.front().first; Q.pop();
while (pare != root && !pare->fail->next.count(c))
pare=pare->fail;
if (pare == root) fill->fail = root;
else fill->fail = pare->fail->next[c];
if (fill->fail->id.size() != 0)
fill->output = fill->fail;
else fill->output = fill->fail->output;
for (MCP::iterator it=fill->next.begin();
it!=fill->next.end();++it)
Q.push(pair<char,P>(it->first,P(fill,it->second)));
}
}
void match(int c, VI& id) {
for (int i = 0; i < id.size(); ++i) {
cout << "Matching of pattern " << id[i];
cout << " ended at " << c << endl;
}
}
void search(string& s) {
int i = 0, j = 0;
Node *p = root, *q;
while (j < s.size()) {
while (p->next.count(s[j])) {
p = p->next[s[j++]];
if (p->id.size() != 0) match(j - 1, p->id);
q = p->output;
while (q != NULL) {
match(j - 1, q->id);
q = q->output;
}
}
if (p != root) {
p = p->fail;
i = j - p->size;
}
else i = ++j;
}
}
void erase(Node* p = root) {
for (MCP::iterator it = p->next.begin();
it != p->next.end(); ++it)
erase(it->second);
delete p;
}
int main() {
init();
int n;
cin >> n;
for (int i = 0; i < n; ++i) {
string s;
cin >> s;
add(s, i);
}
fill_fail_output();
string text;
cin >> text;
search(text);
erase(root);
}

How to compare string variable to constant string in visual c++?

I have this piece of code:
#include "stdafx.h"
#include "afx.h"
...
char * connectionType;
...
int readParameters() {
...
//hFile is a file handler previously initialized
result = readParameter(hFile, connectionType);
if (strcmp(connectionType, "3") == 0) {
//do something
} else {
//do other thing
}
...
}
int readParameter(HANDLE hFile, OUT char * buffer) {
BOOL bResult = true;
BOOL continueLine = true;
char inBuffer[1];
DWORD bytesToRead = 1;
DWORD bytesRead = 0;
OVERLAPPED stOverlapped = {0};
char parameter[256] = {};
int counter = 0;
while (continueLine) {
bResult = ReadFile(hFile, inBuffer, sizeof(char), &bytesRead, &stOverlapped);
if (!bResult) {
return 0;
} else if (inBuffer[0] == '\n' || bytesRead == 0) {
continueLine = false;
} else {
parameter[counter] = inBuffer[0];
counter++;
if (bResult && bytesRead == 0) {
continueLinea = false;
}
}
}
parameter[counter] = '\0';
memcpy(buffer, parameter, 256);
return 1;
}
By debugging, I know that the connectionType attribute ends up being a null terminated string "3", but the strcmp method keeps returning 3328 (>0). Is there a problem because "3" is a constant? What might be the problem?
I realized what was the problem with the code. The problem was that connectionType, whose value was a null terminated string "3", was in fact different to the line read from the file, which was actually a "3" plus a carriage return plus a null.
After I added that consideration to the code, my problem was solved.

shell execute with c++

I am working on an application that will trigger a UAC prompt in whatever program is opened by ShellExecute.
I can't figure out how to hard-code a path for the ShellExecute to run. As of now this program uses whatever path is in arg[0]. How can I build a string to put in the place of arg[0] on the line sinfo.lpFile = arg[0];?
I am very new so if you can't see why making a string to put in that line will solve my problem then you are most likely right.
#include "stdafx.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <shellapi.h>
#include <process.h>
#include "uac-example.h"
int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst,LPSTR cmdLine, int nCmdShow){
LPWSTR *arg;
int argc = 0;
HRESULT ret = SUCCESS;
WCHAR imagePath[MAXPATHLEN];
WCHAR workingDir[MAXPATHLEN];
WCHAR uacDir[MAXPATHLEN];
WCHAR uacRunningLockFilePath[MAXPATHLEN];
HANDLE uacRunningLockFileHandle = INVALID_HANDLE_VALUE;
WCHAR elevatedLockFilePath[MAXPATHLEN];
HANDLE elevatedLockFileHandle = INVALID_HANDLE_VALUE;
arg = CommandLineToArgvW(GetCommandLineW(),&argc);
//if(arg == NULL || argc < 2) {
// ERRORBOX("Missing required program arguments.\n\nUsage:\nuac-example.exe <working directory>");
// return FAILURE;
//}
GetModuleFileName(NULL, imagePath, MAXPATHLEN);
arg[0] = imagePath;
wcscpy_s((wchar_t *)uacDir, MAXPATHLEN, arg[1]);
_snwprintf_s(uacRunningLockFilePath, MAXPATHLEN, MAXPATHLEN,
_T("%s/") _T(RUNNING_LOCK_FILE), uacDir);
wcscpy_s(workingDir, MAXPATHLEN, imagePath);
WCHAR *slash = wcsrchr(workingDir, '\\');
wcscpy_s(slash, MAXPATHLEN, _T(""));
_snwprintf_s(elevatedLockFilePath, MAXPATHLEN, MAXPATHLEN,_T("%s/") _T(ELEVATE_LOCK_FILE), workingDir);
uacRunningLockFileHandle = CreateFileW(uacRunningLockFilePath,(GENERIC_READ | GENERIC_WRITE),0,NULL,OPEN_ALWAYS,FILE_FLAG_DELETE _ON_CLOSE,NULL);
if (uacRunningLockFileHandle == INVALID_HANDLE_VALUE) {
if (_waccess(elevatedLockFilePath, F_OK) == 0 &&
_wremove(elevatedLockFilePath) != 0) {
return FAILURE;
}
elevatedLockFileHandle = CreateFileW(elevatedLockFilePath,(GENERIC_READ | GENERIC_WRITE),0,NULL,OPEN_ALWAYS,FILE_FLAG_DELETE _ON_CLOSE,NULL);
if(elevatedLockFileHandle == INVALID_HANDLE_VALUE){
ERRORBOX("Unable to acquire the necessary permissions to run demo app.");
return FAILURE;
}
LPWSTR spawnCmdLine = BuildCommandLine(argc - 1, arg + 1);
if(!spawnCmdLine){
CloseHandle(elevatedLockFileHandle);
ERRORBOX("An error occured while respawning self.");
return FAILURE;
}
SHELLEXECUTEINFO sinfo;
memset(&sinfo, 0, sizeof(SHELLEXECUTEINFO));
sinfo.cbSize = sizeof(SHELLEXECUTEINFO);
sinfo.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS;
sinfo.hwnd = NULL;
sinfo.lpFile = arg[0];
sinfo.lpParameters = spawnCmdLine;
sinfo.lpVerb = L"runas"; // <<-- this is what makes a UAC prompt show up
sinfo.nShow = SW_SHOWMAXIMIZED;
BOOL result = ShellExecuteEx(&sinfo);
LocalFree(spawnCmdLine);
if(result){
WaitForSingleObject(sinfo.hProcess, INFINITE);
CloseHandle(sinfo.hProcess);
return SUCCESS;
}else{
return FAILURE;
}
}
EXIT_IF_ELEVATED(elevatedLockFilePath,uacRunningLo ckFileHandle,SUCCESS);
LocalFree(arg);
return SUCCESS;
}
// ----------------------------------------------------------------------
// The following code was taken directly from the Mozilla Firefox Updater
// source tree, and slightly modified to support "Wide" strings in
// Visual C++.
// ----------------------------------------------------------------------
LPWSTR
BuildCommandLine(int argc, LPWSTR *argv){
int i;
int len = 0;
// The + 1 of the last argument handles the
// allocation for null termination
for (i = 0; i < argc; ++i) {
len += ArgStrLen(argv[i]) + 1;
}
// Protect against callers that pass 0 arguments
if (len == 0) {
len = 1;
}
LPWSTR s = (LPWSTR)malloc(len * sizeof(LPWSTR));
if (!s) {
return NULL;
}
LPWSTR c = s;
for (i = 0; i < argc; ++i) {
c = ArgToString(c, argv[i]);
if (i + 1 != argc) {
*c = ' ';
++c;
}
}
*c = '\0';
return s;
}
int
ArgStrLen(LPWSTR s) {
int backslashes = 0;
int i = wcslen(s);
BOOL hasDoubleQuote = wcschr(s, L'"') != NULL;
// Only add doublequotes if the string contains a space or a tab
BOOL addDoubleQuotes = wcspbrk(s, L" \t") != NULL;
if (addDoubleQuotes) {
i += 2; // initial and final duoblequote
}
if (hasDoubleQuote) {
while (*s) {
if (*s == '\\') {
++backslashes;
} else {
if (*s == '"') {
// Escape the doublequote and all backslashes preceding the doublequote
i += backslashes + 1;
}
backslashes = 0;
}
++s;
}
}
return i;
}
LPWSTR
ArgToString(LPWSTR d, LPWSTR s) {
int backslashes = 0;
BOOL hasDoubleQuote = wcschr(s, L'"') != NULL;
// Only add doublequotes if the string contains a space or a tab
BOOL addDoubleQuotes = wcspbrk(s, L" \t") != NULL;
if (addDoubleQuotes) {
*d = '"'; // initial doublequote
++d;
}
if (hasDoubleQuote) {
int i;
while (*s) {
if (*s == '\\') {
++backslashes;
} else {
if (*s == '"') {
// Escape the doublequote and all backslashes\
// preceding the doublequote
for (i = 0; i <= backslashes; ++i) {
*d = '\\';
++d;
}
}
backslashes = 0;
}
*d = *s;
++d; ++s;
}
} else {
wcscpy(d, s);
d += wcslen(s);
}
if (addDoubleQuotes) {
*d = '"'; // final doublequote
++d;
}
return d;
}
Simply as:
char path[] = "C:\\program.exe";
sinfo.lpFile = path;

Resources