The public part of the UrlList class contains only methods as usual. Starting with the constructor we see it initializing the head and the tail of the list to NULL since when the list is instantiated it’s empty. This is used to the isEmpty method which checks if the head points where the tail does to NULL and returns true. After in the implementation we meet the print and the checkIfExists methods. Actually the are quite similar since the first traverses the list and in each loop it calls the print method of the corresponding data object while the second one receives as parameter an object and traverses the list until the ends and calls the print method of every data object that matches the parametrically passed one (if (Node->data= = temp)).
As well as the above two methods are similar the insert and append methods are identically the same except two lines of code where the insert puts the newNode as head of the list and the append as the tail of the list. It receives as a parameter the same object as all the above that receive object parametrically and assigns to the newNode created dynamically the values of the temporary (newNode->Data=temp;). After that it checks if the list is Empty and if true is returned the newNode is both the head and the tail of the list. Else depending on if method is the insert or the append it follows the afore mentioned procedure.
Coming to the file manipulation there are two methods that make it feasible. The intro(_) used when the program starts running and it has to load the data line by line from the file to the Nodes of the list. As well the exodus(_) method outputs the data of all the Nodes in the external file before the user terminates the program. In order to explain the way that the methods operate it’s better to start with the exodus method because it actually operates before the intro method (to load something there must be something saved in the file). First in the exodus then we create an output file stream instance and we connect it to the external file. If this already exists it’s opened for output and connected to the output steam out_file. If it does not exist a new one is created. Then we traverse the list and output the returns of each data instance getData methods with the end line operator. So every attribute is saved alone in a single line thus in the file we may have a structure like the following
The Intro method is quite more complicated. First of all it creates three variables same type as the attributes if the ftp class to hold the values we will from the file this is why their names are quite the same adding ‘_file’ to the end. Also we need a character variable to check the eof character of the file. We create an input file stream instance and we connect it to the external file. After that we check if the file exists (some compilers like MS visual C++ create a file with the specified name). For that reason we check then if the first character is the eof. If yes then there is nothing to read and exit. Then while the eof is not the next character we create a new node which we initialize it’s attributes by assigning the values we read from each line to the corresponding afore mentioned variable and then call the node’s setData methods passing the ‘_file’ variables as parameters. Then we append the newNode to the list.
In part of the report some known bugs are reported along with some possible solutions whenever they are known but not implemented for some reasons. The first known bug is founded in the display of the menu and generally in the main program. The final output messages should be displayed before the screen clears and the menu is displayed again. For unknown reasons even if the system(“cls”) command is before the display_menu function the program insists on clearing the screen then finish with it’s operation although it’s in a loop and after display the menu. These are basic programming skills that are mastered by the programmer but no matter what he tried (the clear screen was in the end of case ‘x’ but it still was doing the same thing, or in the appropriate list method) this was not working. If though it was working then we should place the system(“pause”) command before the clear screen so as the user could see the result for as long as he wants and then continue.
Next one in the intro( ) method of the linked list. It appends an extra node in the linked list that its data values are nothing (probably the newline character). This is solved if we remove the ‘endl’ from the third out_file operation of the exodus method. But when we removed it there was another bug in the data as shown bellow
Also we could use a garbage array of characters where we could assign the problematic newline character but this as well was producing the same bug as above even if the logic seems correct. Finally a more off-beat solution could be to delete the last Node exactly after the execution of the intro method. Although the method is implemented as shown in the extra methods section it never managed to work with the rest of the software and was crashing immediately so we suppose that a logical error is hidden somewhere but it could not be debugged.
The last known bug is in the checkIfExists method which asks from the user to create a temporary ftp instance and compare it with all the others in the list and print all those who match the criteria (if(strcmp(domain, temp.domain)&&!strcmp(usrname, temp.usrname)&&!strcmp(password, temp.password))). There should be a way though to print a message of there in no node matching even if the list is not empty. Thus we have the check if(tail->data!=temp) cout<<"Such record does not exist\n"; ) This says that if the whole list is traversed and the last node does not match then there is no such record. It was working perfect with two nodes, but with more it outputs the message every time, since there could be a node in the list matching and the tail would not much.
Before presenting the source codes of the software some extra methods are reported where most of them were implemented but they were crashing for unknown reasons thus they were never debugged. Those methods would ‘increase’ the modularity or the functionality of the software while some could solve some bugs. First is the input-output operator overloading. This would increase definitely the software’s modularity and reusability since we could use them is many other methods as explained bellow after the source codes of those semi-implemented methods.
We could use the output operator very simply by calling the object as variable (i.e. cout<<tmp->data;) This could be used in all cases where we want to print the attributes or to output them in a file (i.e. out_file <<tmp->data<<endl;) Also we could use the input operator where we want to set the data to an ftp instance or in the input from a file by altering the above code a little.
After the input/output operators we could also solve the bug in the ifstream operation by deleting the last node as afore mentioned. The source code of this is given bellow. This as well never worked normally for unknown reasons and was crashing the whole program.
Two more methods are those that would be used in the encryption/decryption of the data during the exodus/intro methods execution correspondingly. Those methods very simple and identically the same but they both never worked correctly as they were crashing the whole program even if there were no compiling errors or warnings.
Finally a method that was partial implemented is the insertInPlace method which would insert a new Node is a place according to specific criteria. The problem in the implementation of this method is that the programmer could not find any criteria (i.e. alphabetical order does not work since all domain names start with ‘www’). As well imagine that we have found something and we have located the correct position in the list by traversing it from the head to the desired node. So we could simply change the next pointers by those two steps (the tmp pointer points to the node that will be before the newNode after the insertion) newNode->next=tmp->next;
Tmp->next=newNode;
Data.h
- #ifndef _DATA_H
- #define _DATA_H
- #include <fstream.h>
- #include <string.h>
- class ftp
- {
- private: //class attributes
- char domain[30];
- char usrname[30];
- char password[8];
- public: //class methods
- ftp(); //constructor
- void printData() const;
- bool ftp::operator==(const ftp &temp);
- bool ftp::operator!=(const ftp &temp);
- void ftp::operator=(const ftp &temp);
- //set methods (modifiers)
- void setDomain(char *tmp_domain);
- void setUserName(char *tmp_usrname);
- void setPassword(char *tmp_password);
- //get methods (assessors)
- char * getDomain();
- char * getUserName();
- char * getPassword();
- };
- //end of class definition
- //----------------------------------------------------
- ftp::ftp()
- {
- }
- //----------------------------------------------------
- bool ftp::operator==(const ftp &temp)
- {
- if(!strcmp(domain, temp.domain) && !strcmp(usrname, temp.usrname) && !strcmp(password, temp.password))
return true;
- else
return false;
- }
- //----------------------------------------------------
- bool ftp::operator!=(const ftp &temp)
- {
- if(strcmp(domain, temp.domain)&&!strcmp(usrname, temp.usrname)&&!strcmp(password, temp.password))
return true;
- else
return false;
- }
- //----------------------------------------------------
- void ftp::operator=(const ftp &temp)
- {
- strcpy(domain, temp.domain);
- strcpy(usrname, temp.usrname);
- strcpy(password, temp.password);
- }
- //----------------------------------------------------
- void ftp::printData() const // accessor
- {
- cout<<"The domain name is: "<<domain<<"\n";
- cout<<"The ftp username is: "<<usrname<<"\n";
- cout<<"The ftp password is: "<<password<<"\n";
- }
- //----------------------------------------------------
- //set methods are used to copy the data from the temporary object
- //could be one method setData but separated it can be used to set/change only one attribute
- void ftp::setDomain(char *tmp_domain)//modifier
- {
- strcpy(domain, tmp_domain);
- }
- void ftp::setUserName(char *tmp_usrname)//modifier
- {
- strcpy(usrname, tmp_usrname);
- }
- void ftp::setPassword(char *tmp_password)//modifier
- {
- strcpy(password, tmp_password);
- }
- //end of set methods
- //----------------------------------------------------
- ////get methods are used to copy the data to the temporary object
- char* ftp::getDomain()//accessor
- {
- return domain;
- }
- char* ftp::getUserName()//accessor
- {
- return usrname;
- }
- char* ftp::getPassword()//accessor
- {
- return password;
- }
- //end of get methods
- #endif _DATA_H
UrlList.h
- #ifndef _URLLIST_H
- #define _URLLIST_H
- #include <fstream.h>
- #include <stdlib.h>
- #include "data.h"
- template <class T>
- //-------------------------------------------------------
- //declare the class at the beginning so as to use it as a friend in the class Node
- class UrlList;
- //-------------------------------------------------------
- //class Node
- template <class T>
- class Node //class Node needs no other methods than the constructor
- {
- public:
- Node() : next(0) { }
- friend UrlList<T>;
- private:
- //The three data parts of each Node in an object of class ftp.
- ftp data;
- //The next pointer of each node
- Node<T> *next;
- };
- //-----------------------------------------------------
- //class UrlList
- template <class T>
- class UrlList
- {
- public: //class methods
- UrlList(); //constructor
- bool isEmpty() const; //check if the list is empty
- void print () const; //print all the nodes
- void checkIfExists(const ftp &temp); //print a specific node accessed by domain name
- void exodus() const;
- void intro();
- void insert(const ftp &temp); //temp object passed as parameter
- void append(const ftp &temp); //temp object passed as parameter
- void deleteNode(const ftp &temp); //temp object passed as parameter
- void deleteAll (); //delete all objects from the list
- private: //class attributes
- Node<T> *head;
- Node<T> *tail;
- int length;
- };
- //end of class definition
- //----------------------------------------------------
- // Constructor
- template <class T>
- UrlList<T>::UrlList()
- {
- head = NULL;
- tail = NULL;
- length = 0;
- }
- //----------------------------------------------------
- // Checks if the list is empty
- template <class T>
- bool UrlList<T>::isEmpty() const
- {
- return head == 0;
- }
- //----------------------------------------------------
- // Prints all the nodes of the list
- template <class T>
- void UrlList<T>::print() const
- {
- //create a temporary pointer so as to traverse the list
- Node<T> *tmp;
- int i=1;
- // start from the head until the end of the list
- for (tmp = head; tmp; tmp = tmp -> next )
- {
- //print the data part of the current node
- cout<<"\n Node number "<<i<<"\n\n";
- tmp ->data.printData();
- i++;
- }
- delete tmp;
- }
- //-----------------------------------------------------
- // Checks if a specific record exists
- template <class T>
- void UrlList<T>::checkIfExists(const ftp &temp)
- {
- //create a temporary pointer so as to traverse the list
- Node<T> *tmp;
- // start from the head until the end of the list
- for (tmp = head; tmp; tmp = tmp -> next)
- {
- //check if the domain is the one wanted
- if(tmp->data==temp)
- //print the data part of the current node
- tmp ->data.printData();
- }
- if(tail->data!=temp)
- cout<<"Such record does not exist\n";
- delete tmp;
- }
- //-----------------------------------------------------
- // Inserts a node at the beginning of the list
- template <class T>
- void UrlList<T>::insert(const ftp &temp)
- {
- //create a new Node
- Node<T> * newNode = new Node<T>;
- //set the data
- newNode->data=temp;
- //if the list is empty then the new node is both head and tail
- if (head == 0)
- head = tail = newNode;
- //else the newNode is the head of the list
- else
- {
- newNode -> next = head;
- head = newNode;
- }
- length++;
- }
- //-----------------------------------------------------
- // appends a node to the end of the list
- template <class T>
- void UrlList<T>::append(const ftp &temp)
- {
- //create a new Node
- Node<T> * newNode = new Node<T>;
- //set the data
- newNode->data=temp;
- //if the list is empty then the new node is both head and tail
- if (head == 0)
- head = tail = newNode;
- //else the newNode is the head of the list
- else
- {
- tail ->next= newNode;
- tail=newNode;
- }
- length++;
- }
- //-----------------------------------------------------
- // Deletes a node from the list accessed by the domain name
- template <class T>
- void UrlList<T>::deleteNode(const ftp &temp)
- {
- if(head->data==temp)
- head = head->next;
- else
- {
- //create two temporary pointers to traverse the list
- Node<T> *prevPtr;
- Node<T> *curPtr;
- prevPtr=head;
- curPtr=prevPtr->next;
- // start from the head until the end of the list
- while(curPtr!=0)
- {
- //check if the domain is the one wanted
- if(curPtr->data==temp)
- //Delete the Node
- prevPtr->next=curPtr->next;
- prevPtr=curPtr;
- curPtr=prevPtr->next;
- }
- }
- }
- //-----------------------------------------------------
- // Deletes all the list
- template <class T>
- void UrlList<T>::deleteAll()
- {
- head=tail=NULL;
- }
- //-----------------------------------------------------
- template <class T>
- void UrlList<T>::exodus() const
- {
- ofstream out_file;
- out_file.open("a:\\myfile.txt", ios::out);
- if (!out_file)
- {
- cout << "Can not create file";
- exit(0);
- }
- //create a temporary pointer so as to traverse the list
- Node<T> *tmp;
- // start from the head until the end of the list
- for (tmp = head; tmp; tmp = tmp -> next)
- {
- out_file <<tmp->data.getDomain()<<endl;
- out_file <<tmp->data.getUserName()<<endl;
- out_file <<tmp->data.getPassword()<<endl;
- }
- out_file.close();
- }
- //-----------------------------------------------------
- template <class T>
- void UrlList<T>::intro()
- {
- char ch;
- char domain_File[30];
- char userName_File[30];
- char password_File[8];
- ifstream in_file;
- in_file.open("a:\\myfile.txt", ios::in);
- if (!in_file)
- {
- cout << "Can not find file";
- exit(0);
- }
- in_file.get(ch);
- if ( !in_file.eof() )
- in_file.putback( ch );
- while ( !in_file.eof() )
- {
- //create a new Node
- Node<T> * newNode = new Node<T>;
- in_file.getline(domain_File,30);
- newNode->data.setDomain(domain_File);
- in_file.getline(userName_File,30);
- newNode->data.setcarryUserName(userName_File);
- in_file.getline(password_File,8);
- newNode->data.setPassword(password_File);
- //if the list is empty then the new node is both head and tail
- if (head == 0)
- head = tail = newNode;
- //else the newNode is the head of the list
- else
- {
- tail ->next= newNode;
- tail=newNode;
- }
- length++;
- }
- in_file.close();
- }
- #endif _URLLIST_H
main.cpp
- #include <iostream>
- #include <fstream.h>
- #include <string.h>
- #include "UrlList.h"
- #include "data.h"
- UrlList <ftp> list;
- ftp temp;
- void setTemporaryData();
- void display_menu();
- void main()
- {
- list.intro(); //before everything starts load the data from the file to the list
- char choice;
- while(choice!='7')
- {
- system("cls");
- display_menu(); //display menu after every operation
- cin>>choice;
- switch (choice)
- {
- //---------------------------
- case '1':
- cout<<"Enter the data of the record you want to insert\n";
- setTemporaryData();
- list.insert(temp);
- cout<<"Record saved\n";
- break;
- //---------------------------
- case '2':
- cout<<"Enter the data of the record you want to append\n";
- setTemporaryData();
- list.append(temp);
- cout<<"Record saved\n";
- break;
- //---------------------------
- case '3':
- if(list.isEmpty())
- cout<<"There is nothing to print\n";
- else
- list.print();
- break;
- //---------------------------
- case '4':
- if(list.isEmpty())
- cout<<"There is nothing to check\n";
- else
- {
- setTemporaryData();
- list.checkIfExists(temp);
- }
- break;
- //---------------------------
- case '5':
- if(list.isEmpty())
- cout<<"There is nothing to delete\n";
- else
- {
- cout<<"Enter the data of the record you want to delete\n";
- setTemporaryData();
- list.deleteNode(temp);
- }
- break;
- //---------------------------
- case '6':
- list.deleteAll();
- list.exodus();
- break;
- //---------------------------
- case '7':
- list.exodus();
- cout<<"Your Data is saved\n";
- cout<<"exit to DOS\n";
- break;
- //---------------------------
- default:
- cout<<"\n invalid choice!!\n";
- break;
- //---------------------------
- }
- }
- }//end of main function
- void display_menu() //display the menu
- {
- cout<<"|------------------------------------|\n";
- cout<<"| .::Menu::. |\n";
- cout<<"|------------------------------------|\n";
- cout<<"| 1. Insert new record |\n";
- cout<<"| 2. Append new record |\n";
- cout<<"| 3. Print all the records |\n";
- cout<<"| 4. Check if a record exists |\n";
- cout<<"| 5. Delete a specific record |\n";
- cout<<"| 6. Delete all the records |\n";
- cout<<"| 7. Save and Exit |\n";
- cout<<"|------------------------------------|\n";
- cout<<"| Make your choice... |\n";
- cout<<"|____________________________________|\n";
- }
- void setTemporaryData()
- {
- char tmp_domain[30];
- cout<<"Input the domain name\n";
- cin>>tmp_domain;
- char tmp_usrname[30];
- cout<<"Input the user name\n";
- cin>>tmp_usrname;
- char tmp_password[8];
- cout<<"Input the password\n";
- cin>>tmp_password;
- temp.setDomain(tmp_domain);
- temp.setUserName(tmp_usrname);
- temp.setPassword(tmp_password);
- }
Instructor Mr. Hatziapostolou -