Banfa 597 Posting Pro Featured Poster

Assume a class declared like this (I have reduce it to 1 float for berevity)

class MyClass
{
public:
    MyClass(float initx);
    setX(float newx);

private:
    float x;
}

You are say since the constructor is implemented as

MyClass::MyClass(float initx)
{
    x = initx;
}

you could just call setX which does the same thing. The mistake is that you are assign in the constructor when it is more preferable to use initialiser lists so you constructor should really be

MyClass::MyClass(float initx)
: x(initx)
{
}

Nothing like setX!

A float is a simple case but get into the habit of using intiialiser lists. You will often want to use them if you have a class hierarchy anyway to initialise base classes in a specific way.

if the constructor calls some code that is also called by a class method then probably the best thing to do is to put the code into a private method that both the constructor and public member call. That is separate the implementation from the interface. Also also allows for such things as differing checks on data validity before calling the common code.

Banfa 597 Posting Pro Featured Poster

Actually this piece of code is not really interested in the sub-class at all. It just needs a Request* in order to queue the request.

It looks like you could use a factory method. A factory method is often a static member of a base class that accepts data and uses the data to create a sub-class of that base but returns a base class pointer.

This keeps the code the knows how and when to create the sub-classes nicely encapsulated in the class your code you then look something like

Request *request=Request::requestFactory(line);

	if (request != NULL)
	{
		requests.enqueue(request);
	}

The factory method looks something like

Request::requestFactory(const QSTring& line)
{
	RequestTypeType requestType = <Decode type From Line>;
	Request* retval = NULL;

	switch(requestType)
	{
	case REQUEST_LOGIN:
		request= new LoginRequest;
		request->tcpMessage=line.toUtf8();
		request->decodeFromTcpMessage();
		break;

	case OTHER_REQUEST_TYPE:
		request= new OtherRequestType;
		request->tcpMessage=line.toUtf8();
		request->decodeFromTcpMessage();
		break;

	...
	}

	return request;
}
metdos commented: Nice, Clean , Informative answer +1
Banfa 597 Posting Pro Featured Poster

There is no standard library functions in C for serial port access because it is too platform dependent.

The Win32 API does support serial ort access however mildly confusingly you have to use CreateFile to open a serial port and ReadFile and WriteFile to read and write data to it.

There are a bunch of specific comfiguration and tuning functions reference available here.

Banfa 597 Posting Pro Featured Poster

The problem is at line 12 loginRequest is created on the stack, that means that it is automatically has the lifetime of the code block it is in which is the if statement.

You take pointers to it and put them on your queue but that doesn't change the fact that the original object is deleted when its lifetime expires.

You need an object whos lifetime is not limited to the code block it is created in. That would be an object allocated from the heap using new.

Change how you use your queue so that the pointers it contains always point to objects allocated using new. When you remove items from the queue remember to delete them once you are finished with them. Possibly look into using std::auto_ptr or a smart pointer or handle class.

Is there any reason you didn't use a std::queue? Is QQueue at QT class?

Banfa 597 Posting Pro Featured Poster

Line 14 coupled with lines 17 and 21 result in a big error. int binary[31]; defines an array of integers with 31 entries in the array indexed as 0 - 30. Certainly not enough to hold a value for each bit in a 32 bit value. for(y = 32; y >= 0; y--) You iterate through the loop 33 times once weach for every value between 32 and 0. Clearly an error when trying to evaluate a 32 bit integer. binary[(32-y)] = x; combined with the previous 2 errors you access array indexes 31 and 32 when y is respectively 1 and 0 both of which are out of bounds array accesses and result in undefined behaviour.

On the algorithm had it been coded correctly. All that raising to powers and reverting to floating point arithmetic is incredibly inefficient not to mention if you were going to do that why not use pow from the standard library rather than write your own.

However the whole affair can be much more simply and efficiently code by using the operators that work directly on bits, this set of operators include

bitwise AND &
bitwise OR |
bitwise NOT ~
bitwise XOR ^
shift left <<
shift right >>

You can use AND to isolate the value of specific bits you can use the shift operators to control which bit you are currently examining.

Banfa 597 Posting Pro Featured Poster

You have not fully taken on board the nature of floats (and doubles). it has nothing to do with the machine being 32 bits, it is the nature of how floats hold there values that they are approximations (normally good ones) that is a float is rarely 2.5 or 3.0 it will be 2.499999 or 3.00001 with the possible exception of a float variable immediately following initialisation.

You are multiplying by 100 and then trying to test the remaining decimal places to see if they are 0 and if they are not 0 rounding up. However because of this aprroximate behaviour except for a variable immediately following initialisation so any value that has been calculated you have to assume that the digits following the ones you are interested in are always non-zero.

Even for the simple multiplication * 100. A float may be able to hold 2.500 exactly and it may be able to hold 250.00 exactly but 2.500 * 100.0 could result in 249.99.

So under the assumption that the trailing digits of a floating point variable following some calculations are never 0 and the strict definition of rounding up you will always be rounding up.

In that case you can save yourself the hassle of the calculation, * 100 truncate and + 1.

That is probably not want you want to here but that is the nature of floats.

Your only other option is what you have suggested, choose a tolerance that …

Ancient Dragon commented: very nice :) +27
Banfa 597 Posting Pro Featured Poster

In your function x and z are input arguments because they are passed by value. What ever the function does it can not alter the value of x and z in the calling code.

*y (note not y) could already be an in, out or inout parameter because the function can alter the value of *y in the calling code but you can tell if it actually does without seeing the function code or description.

For a parameter to be an out or inout parameter it must passed a reference to the variable in the calling code, even if it does it the old C way of passing a pointer to the variable by value.

Your best bet is to write some code and experiment a bit with the various ways of passing a parameter to a function and seeing what happens if you try to alter the parameter in the function.

Banfa 597 Posting Pro Featured Poster

In general you can only differentiate between them by looking at the code of the function or the function documentation.

However that said an argument passed by value, constant reference or constant pointer is an input argument.

An argument passed by non-constant reference or non-constant pointer could be an in, out or inout argument.

Banfa 597 Posting Pro Featured Poster

Then you are probably compiling as C++ rather than C.

What is the file name?
What compiler command line/IDE are you using?

Banfa 597 Posting Pro Featured Poster

An agregate type is a structure or class or union that holds (possibly) an agregate of serveral members of other types.

In you print function you do not have an agregate type you have a pointer to an aggreagate type. You can get the agregate type by dereferencing the pointer so for a structure type T

T obj;
T* pointer = &obj;  // Always initialise pointers

obj.member;  // Access a member of an agregate type

pointer.member;  // Error pointer is not an agregate type it is a pointer to an agregate type

(*pointer).member;  // OK pointer is derefernced to the agregate type 

pointer->member;   // The -> operator is a shortcut for above syntax
Banfa 597 Posting Pro Featured Poster

Sorry, what are you trying to do????

Why would you want to copy the string before allocating it? Generally the way round to do things is allocate the memory for an object and then copy the data into the object.

You can not assign to the return value of strcpy or any other function in C.

strcpy takes 2 arguments, destination and source.

When you allocate through malloc you need to allocate enough memory for the object you want to hold. You have allocate sizeof(char) or 1 byte but you want to hold a string so you need at least the length of the string plus 1 (for the terminator) bytes.

Your function always returns NULL, if the rest of if worked the pointer to the allocated memory would be lost resulting in a memory leak.

Banfa 597 Posting Pro Featured Poster
stable = std::auto_ptr<MyClass> ( new MyClass() );

Yes me too :-) !

I hadn't tried the compile but looking at it and assuming it would work (due to its source) I was asking myself the question, surely the auto_ptr would delete the object as soon it went out of scope, which since it is anonymous is the end of the statement.

EDIT: Never mind you edit and a quick refresher of the auto_ptr reference clears it all up.

Banfa 597 Posting Pro Featured Poster

start quote:

main()
{
           int a;
           a=message();
}
message()
{
          printf("\n C language");
}

what is the output and what return will return to a;

Since this is the C++ forum there would be no output from that since C++ does not support implicit types on functions or calling functions without a prototype so the code will not compile.

Assuming that you meant to compile it as C and that you are willing to ignore the warnings produced rather than fix them then the output of the code is either undefined behaviour or extremely platform defined.

WaltP commented: Another 3 year resurrection... +11
Banfa 597 Posting Pro Featured Poster

You might try by finding out where the segmentation fault occurs either by using a symbolic debugger or if one is unavailable the more sedge hammer method of commenting out bits of code until you find the bit that causes the crash.

However I suspect that pass the buffer size rather than the amount of data received to the dycryption functions is a mistake as it will presumably be trying to decrypt the random data in the buffer following the actualy received data.

You are also making some false assumptions about you networking communications. You are using SOCK_STREAM so presumably a tcp socket. A tcp socket provides a coonection based byte stream. However you have assumed that it is packetised. That is you have assumed that for every transmit (send) called at the client your sever will receive precisesly i receive (recv) call.

That is just not true. Imagine your client calls send 3 times to send 3 bunches of encrypted data. Your server may receive the whole lot in 1 recv call or it may need to call recv more than 3 times to receive all the data.

I suggest you read Beej's Guide to Network Programming which IMO is quite a good primer.

Banfa 597 Posting Pro Featured Poster

When LoadLibrary fails it must be for a reason. Assuming that you have the path correct I suggest you call and print the return value from GetLastError to get some clarificaion of what is causing the problem.

You can look up the value returned from GetLastError in winerror.h

Banfa 597 Posting Pro Featured Poster

it is not about using ifstream multiple times, it is about trying to define the same variable multiple times. ifstream is the type not the variable.

In a for loop it would work because the code body of the loop is executed completely including deleting objects at the end of the iteration for every loop iteration so in a loop you variable infile is created and destroyed on every iteration and there is no attempted redefinition.

To use a different variable just use a different variable name.

Banfa 597 Posting Pro Featured Poster
char *myChar = const_cast <char*> strMyString.c_str ();

In general this is a bad idea, c_str returns const because you should not be changing the data pointed to by its return value. Randomly casting away the constness for no good reason is asking for trouble and undefined behaviour.

cstr = new char [dir.size()+1];
		cstr2 = new char [dir2.size()+1];

		CopyFile(cstr, cstr2, false);

This just creates 2 buffers of the right size without putting anything in them and then passes the unitialised buffers to CopyFile.

You need to see everyone elses comments of string::c_str you may just want to consider looking the method up in your reference material.

tux4life commented: Solid advice :) +8
Banfa 597 Posting Pro Featured Poster

main returns int not void (although that isn't actually causing the error it is quite a serious mistake).

You define infile on both lines 47 and 68. You can only define a variable once in a single code block. You need to either

re-use infile rather than redefining it or use a different variable or (my favourite) split you program up into sensibly sized functions isolating bits of functionality, such as loading 2 files, from each other.

Banfa 597 Posting Pro Featured Poster

operator+= is the in place addition operator. That is it alters the object it is called on, unlike the binary additional operator operator+ which does not alter the object it is called on at all but just returns a new result.

Your impletemtation is not in place, that is it does not alter the object it is called on,it creates a new temporary object temp and alters that.

They way you have written it x += y does not alter x which is what you are seeing. If you wrote z = (x += y) with your current implementation then you would find that x was unaltered by z had the sum of x and y.

You need to re-write your operator+= so that is does an in place calculation, that is so that the object that it is called on is altered to contain the new value. You will not need the variable temp at all in such an implementation.

Banfa 597 Posting Pro Featured Poster

resultsDaily has type double**, to use . you need the thing on the left to have a class/structure/union type.

Even if you dereferenced resultsDaily a couple of time this would not be the case since its basic type is double.

Banfa 597 Posting Pro Featured Poster
Hash h = Hash(string);

1 line of code, h gets created on the first line and initialised with string. 1 object, h, is constructed and destructed.

Hash h;
h = Hash(string);

2 lines of code (well statements they could be on the same line). Line 1 h is created using the default constructor. Line 2 an anonymous temporary object is created and initialised with string and then assigned to h using the assignment operator then the anonymous temporary object is destroyed. 2 objects are constructed, h and the anonymous temporary, and then destructed so there are 2 destructor calls.

It is the difference between initialisation and assignment.

Hash(string) invokes default constructor and creates an object
this object is then copied to 'h' at h= Hash(string)

Banfa 597 Posting Pro Featured Poster

Wrong, destructor gets called twice.
Hash h;
h = new Hash(string);

Destructor gets called once.
Hash h = new Hash(string);

Neither of these are right they attempt to assign an object of type Hash* to an object of type Hash I get the following 2 errors respectively compiling this code.

error: no match for ‘operator=’ in ‘h1 = (operator new(4u), (<statement>, ((Hash*)<anonymous>)))’

error: conversion from ‘Hash*’ to non-scalar type ‘Hash’ requested

Not only that but even if they did work there is no evidence that you have stored the pointers returned by new so that you can later delete them so you would have a memory leak (remember no garbage collection in C++).

Banfa 597 Posting Pro Featured Poster

Next error: look on line 21 and before for the missing ';'

Or with errors of that nature (missing X before Y) look on the first line of code before the line given, 21 in this case particularly if Y is the first thing on the error line.

Banfa 597 Posting Pro Featured Poster

Yep that would be my opinion, don't bind anything let the operating system make its own decision.

A lot of relatively brilliant minds have gone into writing the algorithms that the processor uses to decide which thread/process to run on which core. Supposing you can make a better decision is at best foolish.

You try and run many programs that all suppose they can do the binding better and circumvent the processors own routines and you are likely to tie the processor up in knots and prevent it working at all efficiently.

jonsca commented: Wise +4
Banfa 597 Posting Pro Featured Poster

Lin 6 fills me with some dread. What do you suppose (end-begin) does?

When end and begin where pointers in your array/pointer implementation the answer was obvious but now end and begin are not pointers, they are objects and I am slightly surprised that that construction even compiles as I would not really expect operator- to be implemented for an iterator.

Line 23 and 25 fill me with similar dread but there is some evidence that random access iterators support operator< so it may be OK.

Actually my C++ references seem to be very short on what methods any iterator actually implements and I think it is this (and other similar omissions) that leave me quite dissatisfied with a lot of C++ documentation.

Banfa 597 Posting Pro Featured Poster

Knowing the link command line will not let you know what gets linked into you executable because the linker only includes the bits of a library that are needed and if non of the library is needed then the library might be on the link command line but it is not getting linked into your executable.

If you want to know what has been linked into your executable use a utility like nm that will tell you based on what is in the executable file.

Wanting to know what is going on is commendable but in my opinion you are taking it to an unnecessary level of detail when you could use your time more usefully learning something you will use more often.

However its your time so you may send it how you choose :-)

Banfa 597 Posting Pro Featured Poster

A quick Google produces http://gcc.gnu.org/onlinedocs/gccint/Collect2.html

So the answer (reading that) is no collect2 invokes your linker for you but might well be the program you run when you execute ld.

Everything wraps something else which comes back to my point of why make things complicated trying to invoke ld yourself when you can invoke it through gcc and take the complications out of it. Producing good programs is more than hard enough without setting yourself extra challenges especially when anything you learn doing this will stop applying the moment you start using a different tool chain.

Also note in post #6 I said to invoke gcc on objects not on C files as you implied in post #8.

Salem commented: Nicely put +20
Banfa 597 Posting Pro Featured Poster

Using ios_base didn't seem to work either. Could it have anything to so with it being a class member function? I'm really just grabbing at straws now!

Using iso_base was not the suggestion the suggestion was use iso_base::ate

Banfa 597 Posting Pro Featured Poster

You have not called the function myStrlen, you have output its location in memory, that is myStrlen is not a function call it is a pointer to the function you need myStrlen("Hello World") for a function call.

Banfa 597 Posting Pro Featured Poster

I think you need to be using the style WS_GROUP on line 5 in addition to what you already have.

Banfa 597 Posting Pro Featured Poster

It sounds like your file is somehow getting truncated before you write out the data or that you are writing to a non-existing file. You need to check out both of these possibilities in full first.

This outFile.write((char*)this, sizeof(A)); is a particularly poor way to write out the class data to file. There are many ways this could go wrong on a slightly more complex class (one with a virtual base or in fact any base, one with a pointer to allocated data). You should write out the individual data members of the class not perform this type of conversion.

Banfa 597 Posting Pro Featured Poster

@prushik

You may well find it easier, initially to link through gcc (or g++) Both of these programs are really entry points onto the entire tool chain rather than actual compilers which is why you have to issue them the -c switch to make the only compile. Similarly to can get then to just link by simple putting obejct files on there command line try gcc hello.o -o hello .

Calling through the entry point like this helps because it automatically adds things that are normally the same every time. you can call ld directly if you want but in my opinion it is only worth doing if you really need to call ld in a way that is different to how gcc calls it.


BTW what hasn't been said yet is that for embedded programming there is often (sometimes) a third step after linking as follows

compile
link
locate

Generally all platforms require you compile and link but linking tends to produce a relocatable executable image, that is an executable image that can be run from any memory location. For some embedded platforms they are expecting the image to be in a specific place in platform memory and the program loader is expecting the image to know where it is supposed to be located.

On platforms like this you run the relocatable image through a locator to produce an executable image for a specific location in memory.

Like …

Banfa 597 Posting Pro Featured Poster

In a loop like this

int main()
{
    for(int ix = 0; ix<5; ix++)
    {
        MyObject obj = MyObject(ix);
    }
}

obj is constructed and destricted on every loop iteration. Put cout statements in the constructor and destructor if you wish to confirm it.

Banfa 597 Posting Pro Featured Poster

There is a slight problem here, you have used floats, which I wouldn't say is wrong, but the problem is that floats (and doubles) are approximations to values. What this means is that 2 variables that you and I would say where the same the computer will think is different because it differs in the 7th significant digit.

You can't use == and != on floats and doubles so you can't say that 2 circles definately have the same centre or definately have the same radius.

But if they have the same centre they are concentric and if they have the same radius as well they are the same circle.

You have to write a test for float similarity that has a tolerance, some thing like fabs(float1 - float2) < 0.001, is the absolute difference less than some tolerance.

You can then use this test on the centre of you circles to and you will be able to say the circles are close to concentric and if they also have the same radius they will be close to being the same circle.

You should do these tests first because you do not want to be trying to find the intersections of 2 circles that may be close to being the same circle, there will be a lot of them.

Banfa 597 Posting Pro Featured Poster

Your class has a design flaw, it stores a pointer char *s but you point that pointer at either NULL or at data external to the class.

The class should own its own data allocating what it requires with new and deleting it when finished.

Banfa 597 Posting Pro Featured Poster

EVP_EncrpytInit_ex does not exist in any files or libraries you used to try an link the program.

Either you are missing a library or you have the function name wrong or the function really does not exist anywhere.

I think its the second did you mean EVP_EncryptInit_ex?

Banfa 597 Posting Pro Featured Poster

Like I said it is probably using an extension which compiler are you using?

Banfa 597 Posting Pro Featured Poster

No you need to alter line 14 of your code listing, it still does not refer to a defined type.

Banfa 597 Posting Pro Featured Poster

no you can't my compiler produces this error

bytes.cpp:8: error: ISO C++ forbids variable-size array `a'

Variable size arrays are not part of C++ (they are a part of C99) if your compiler allows that code in C++ then it is using an extension to the standard.

In standard C++ you have to do it by allocating (new) the array once you know the size and deleting it afterwards.

#include <iostream>
using namespace std;

int main()
{
	int x;
	cin>>x;
	int* a = new int[x];
	for(int i = 0;i<x;i++)
	{
		cin>>a[i];
		cout<<"\n"<<a[i];
	}
	
	delete[] a;
	return 0;
}
gaya88 commented: thanks +0
Banfa 597 Posting Pro Featured Poster

This converts->i = 0x1 << 4 | 0x2 << 0; is basically dealing with nibbles (nominally 1/2 a byte, 4 bits) so the value is 0x12 = 18.

However it is normal to deal with bytes not nibbles and that is what ntohl operates on. Not only that but see the l (ell) on the end, that is the function that deals with longs or 4 bytes. It takes 4 bytes in big edian format and converts them to a long value in local machine format which you then output in hex.

What are the first 4 bytes of your array? 0x01, 0x02, 0x03, 0x04
What does it output? 1020304
See the correlation?

I can tell you that it is outputing the correct value given the data you supplied and that your manual calculation is not the calculation that ntohl is doing.

If you want to work on 16bit (short) values you might be better off using ntohs.

Banfa 597 Posting Pro Featured Poster

Sorry I thought that was a very accurate answer to the actual question you posted. Perhaps you should try doing your own homework and then asking more explicit questions if you run into trouble.

I for one am not going to be writing your homework assignment for you and I doubt anyone else here will either.

Here are a few hints

  • You are going to need to check every element in the array so some sort of loop will probably be required

  • You are looking for the largest value so you will need to be doing some comparisons, that means if statements and compaison operators
  • You are looking for more than 1 result so you will possibly require an array to store the results in.
  • To make things simple start by writing a program that just finds the largest value in an array, then once it is working modify it to actually work out the indexes in the array that the value is stored at.

If you only have 10 hours to complete it you better get cracking!

Next time please don't PM me.

Banfa 597 Posting Pro Featured Poster

The problem is (I think) in how you define the structure

typedef struct
{
    int storeNumber;
    char storeName[STORE_NAME_SIZE];
    char phoneNumber[STORE_PHONE_SIZE];
    struct STORE *link;
}STORE;

at line 6, you have no type struct STORE. You have a defined type STORE and an unnamed structure.

if you did this

typedef struct store_t
{
    int storeNumber;
    char storeName[STORE_NAME_SIZE];
    char phoneNumber[STORE_PHONE_SIZE];
    struct STORE *link;
}STORE;

Then you would have a defined type STORE and a structure named store_t or type struct store_t then

struct store_t* ptr1;
STORE* ptr2;

would be equivilent.

Banfa 597 Posting Pro Featured Poster

Yes

Banfa 597 Posting Pro Featured Poster

Trying to simulate the idea is fine but to do that you have to have the correct data in the buffer.

If its a short buffer then use a debugger to set a break point at a point where the buffer is already loaded and copy the data. Alternitively print out the buffer. Alternitively if you have one sniff the data on the wire directly.

What is certain is that the data coming down the wire is not going to be ASCII data like the data you used to initialise your buffer.

Banfa 597 Posting Pro Featured Poster

Of course it prints the ASCII values of 1 and 2, because when you created the string of characters you initialised it with ASCII characters so unsurprisingly that is the values contained.

When you say "I want to read from an array two bytes and print then as a short int" do you mean you want to from an array of 2 bytes containing ASCII values and display them as an integer or do you mean you want to read from an array of 2 bytes containing the binary representation on a short int in big endian format and display the short int value?

In the first case you need to use a function like strtol or aoti and in the second case you have you array initialisation completely wrong you want something like char a[9]={0, 12, 0, 0, 0, 0, 0, 0, 0};

Banfa 597 Posting Pro Featured Poster

You do realise that in the code posted Ancient Dragon had already made that replacement? Ancient Dragon posted compilable code all you have to do is copy what (s)he did and apply it to you other function calls.

Banfa 597 Posting Pro Featured Poster

Your 2 variables intersection and containment are float arrays that are never initialised.

You then access them by incrementing them, which in itself is undefined behaviour. Since they where not initialised they had a random initial value so the value they have after the increment is also random.

Finally you use the test == 0.0 that is never going to work with a float type. floats and double contain approximations to values the == and != operator are pretty much guaranteed to give you wrong answers a large proportion of the time. Not only that but I see not reason why you have used floats for these variables.

To sum up use an appropriate, non floating point, type for intersection and containment and initialise them before you use them.

Banfa 597 Posting Pro Featured Poster

Try SetDlgItemText

Banfa 597 Posting Pro Featured Poster

No there is a way to get the square root of a negative number but as Ancient Dragon says the result is imaginary.

The square root of -1, sqrt(-1) is assigned a special value by mathematicians, i (engineers tend to use j for the same value). You can not actually write a value down for i as you can other constants like PI for instance (3.141...) i is the imaginary number that satisfies the equation

i x i = -1 (i squared equals minus one)

By having i the square root of negative numbers can be calculated because

-624.5 = -1 x 624.5

so

sqrt(-624.5) = sqrt(-1) x sqrt(624.5)

sqrt(-1) = i and we can calculate sqrt(624.5) because it is positive therefore

sqrt(-624.5) = i x sqrt(624.5) = 24.99i

If you square the result you get -624.5 showing that this is the correct square root.

Ancient Dragon commented: good answer :) +27
Banfa 597 Posting Pro Featured Poster

Well you could simple create a line in the file for each string consisting of

StringInQuotes,fan,pan,tan,lan

When you want to test fan responses you read and parse each line of the file. If the line has fan set to 1 then you process the string using the strstr call as you have been doing. If the result is 1 output the appropriate response. If the result is 0 you continue to the next line of the file. If you get to the end of the file without getting a positive hit then output your "don't understand" response.

Alternitively, test the string on each line, if you get a positive match check the fan,pan,tan,lan values to see which response to give otherwise move onto the next line. You could condense fan,pan,tan,lan into a single response value that gives the response to give if the string tests true.

Just open the file and read it a line at a time. Process the line, if you get a response close the file again otherwise move onto the next line. If you get to the end of the file with no response output "don't understand"