candyapplecorn

A VERY Simple Text Editor

Feb 5th, 2014
169
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 19.91 KB | None | 0 0
  1. // NOTE FOR PASTEBIN USERS: I went and attached both the main cpp file and the header file to this paste.
  2. //                          To get this program to work you need to cut out the circularlydoublylinkedlist.h
  3. //                          class towards the end of this file, and paste it into another file and then you
  4. //                          need to build a project including both the main file and the header file.
  5. //                          Oh yeah, also, you need a text file in the directory of the project/.exe. It
  6. //                          has to be named "input.txt". It can contain anything.
  7. //                          tl;dr: cut and paste the class file into a new file, and include it in a project.
  8. //                                 And don't forget to make an input.txt
  9.  
  10. /// Lab 3: A Text Editing Program Using a Circularly & Doubly Linked List
  11. /// 2014-2-3
  12. ///
  13. /// This program uses the class LinkedList, which makes a circularly doubly linked
  14. /// list. This means each node points forwards AND backwards. Additionally, the last
  15. /// node in the list points to the beginning of the list. Or rather, the dummy node in
  16. /// the list. That's right - not only is this program using a souped-up linked list,
  17. /// it's using a sentinel and dummy node too!
  18. ///
  19. ///
  20. ///
  21.  
  22. // This program demonstrates the displayList member function.
  23. #include <iostream>
  24. #include <string>
  25. #include <fstream> // To read from an input file
  26. #include <sstream> // for string stream, used to transfer data from a string filled with getline()
  27. #include <cstring> // for c_str() and other functions
  28. #include "CircularlyDoublyLinkedList.h" // The name describes it pretty well.
  29. using namespace std;
  30.  
  31. const int NUMCOMMANDS = 10;
  32. const string COMMANDS = "TFBILDSHAQ";         // commands stores all ten command codes.
  33.  
  34. bool fillList(LinkedList<string> *list);
  35. void help();
  36. void menu (LinkedList<string> *list);
  37. bool getCommand(string &, LinkedList<string> *list);
  38. void deleteLines(LinkedList<string> *list, int, int);
  39. void listLines(LinkedList<string> *list, int a, int b);
  40.  
  41. int main()
  42. {
  43.     LinkedList<string> *list = new LinkedList<string>; //def a pointer to a linked list object, and then allocate the pointer.
  44.  
  45.     // call fillList to read from an input file into the linked list. if no file found, returns false and program ends.
  46.     if(!fillList(list))
  47.         return 1;
  48.     menu(list);
  49.  
  50.     return 0;
  51. }
  52. // getCommand gets input, validates it and processes it. When the user enters q or Q, the function will return
  53. // false and the program will end.
  54. bool getCommand(string & command, LinkedList<string> *list)
  55. {
  56.     command.clear();                        // clear the string "command" so as not to get improper results
  57.     bool flag = false;                      // flag will be used to see if the user enters a valid command
  58.     int length;                             // for size of the input string
  59.     string temp;
  60.     stringstream stream;                    // used to transfer data from the string "command" to other containers, like int variables
  61.  
  62.     while(!flag)
  63.     {
  64.         cout << "Enter a command: ";
  65.         getline(cin, command);
  66.         length = command.length();
  67.         stream << command;                  // store the input in a string stream for later extraction
  68.  
  69.         for (int i = 0; i < NUMCOMMANDS; i++)
  70.             if (COMMANDS[i] == toupper(command[0])) // Compare each command code to the user string.
  71.                 flag = true;
  72.  
  73.         if (length == 1) // If the length of the string is 1, then skip all other checks and see if flag is true or false.
  74.             continue;
  75.  
  76.         if (command[1] != 32 ) // See if the user seperated the command with a space. No space means improper input, skip to beginning of loop.
  77.         {
  78.             flag = false;
  79.             continue;
  80.         }
  81.         // If the first character in the input is S or s, the program may save the file.
  82.         if (command[0] == 'S' || command[0] == 's')
  83.         {
  84.             int pos = command.find(".txt");
  85.             if (pos == length - 4)
  86.             {
  87.                 flag = true;
  88.                 temp = (command.substr(2, string::npos));
  89.                 list->saveText(temp);
  90.             }
  91.             else
  92.                 cout << "Improper filename.\n";
  93.             continue;
  94.         }
  95.         // If the first character in the input is L or l, the program may list line(s)
  96.         if (toupper(command[0]) == 'L' || toupper(command[0]) == 'l')
  97.         {
  98.             int num1, num2;
  99.             char temp;
  100.             if (stream >> temp >> num1 >> num2)
  101.             {
  102.                 flag = true;
  103.                 // Call list Lines and pass the line numbers.
  104.                 listLines(list, num1, num2);
  105.             }
  106.             continue;
  107.         }
  108.         // If the first character in the input is I or i, the program may inseert a line.
  109.         if (toupper(command[0]) == 'I' || toupper(command[0]) == 'i')
  110.         {
  111.             int num1;
  112.             char temp;
  113.             if (stream >> temp >> num1 && getline(stream,command))
  114.             {
  115.                 command.append(1,'\n');
  116.                 command = command.substr(1, string::npos); // Deletes the space trailing after the number
  117.                 // Call the insertNode function to insert the line
  118.                 list->insertNode(command, num1);
  119.                 flag = true;
  120.             }
  121.             continue;
  122.         }
  123.         // If the first character in the input is D or d, the program may delete line(s)
  124.         if (toupper(command[0]) == 'D' || toupper(command[0]) == 'd')
  125.         {
  126.             int num1, num2;
  127.             char temp;
  128.             if (stream >> temp && stream >> num1 && stream >> num2)
  129.             {
  130.                 flag = true;
  131.                 deleteLines(list, num1, num2);
  132.             }
  133.             continue;
  134.         }
  135.         cout << "Improper input.\n"; // If the loop gets this far, the input is wrong
  136.     }
  137.     if (toupper(command[0]) == 'Q') // Check to see if the user wants to quit
  138.             return false;
  139.     if (toupper(command[0]) == 'T') // List # lines in text
  140.         cout << "There are " << list->getCount() << " lines.\n";
  141.     if (toupper(command[0]) == 'F') // Print all lines
  142.         list->displayList();
  143.     if (toupper(command[0]) == 'B') // Print all lines backwards
  144.         list->displayListReversed();
  145.     if (toupper(command[0]) == 'H') // Display the help dialogue
  146.         cout << "\n\n\n", help();
  147.     if (toupper(command[0]) == 'A') // Display information about the super awesome, mega smert, #1 homework doer
  148.     {
  149.         cout << "Developer: Joseph Burger\n"
  150.              << "           cis22C: Data Structures\n"
  151.              << "           Winter 2014\n"
  152.              << "           De Anza College\n";
  153.     }
  154.  
  155.     return true;
  156. }
  157. // ListLines lists lines a through b. If a > b, then the lines will be listed in reverse order.
  158. void listLines(LinkedList<string> *list, int a, int b)
  159. {
  160.     int numlines;
  161.     if(a < 1 || a > list->getCount() || b < 1 || b > list->getCount())
  162.     {
  163.         cout << "Invalid line numbers.\n";
  164.         return;
  165.     }
  166.  
  167.     if (a > b)
  168.         numlines = a - b + 1;
  169.     else
  170.         numlines = b - a + 1;
  171.  
  172.     for (int i = 0; i < numlines; i++)
  173.     {
  174.         if (a > b)
  175.             list->displayLine(a), a--; // I chose to use the comma operator to save 6 lines of space combined for this if/else block
  176.         else
  177.             list->displayLine(a), a++;
  178.     }
  179.  
  180.     return;
  181. }
  182.  
  183. // deleteLines calls the deleteLine function in the LinkedList class.
  184. // It calls it repeatedly, until it deletes lines a through b inclusive.
  185. void deleteLines(LinkedList<string> *list, int a, int b)
  186. {
  187.     int numlines;
  188.     if(a < 1 || a > list->getCount() || b < 1 || b > list->getCount())
  189.     {
  190.         cout << "Invalid line numbers.\n";
  191.         return;
  192.     }
  193.  
  194.     if (a > b)
  195.         numlines = a - b + 1;
  196.     else
  197.         numlines = b - a + 1;
  198.  
  199.     for (int i = 0; i < numlines; i++)
  200.     {
  201.         if (a > b)
  202.             list->deleteNode(b);
  203.         else
  204.             list->deleteNode(a);
  205.     }
  206.     return;
  207. }
  208.  
  209. // menu displays the help menu, then the program goes into
  210. // a while loop that ends when the user enters q or Q, making
  211. // getCommand return false and ending the program.
  212. void menu (LinkedList<string> *list)
  213. {
  214.     // Display the Help menu
  215.     help();
  216.     // Enter a loop that starts with an input validation function
  217.     string command;
  218.     while (getCommand(command, list)){};
  219.     return;
  220. }
  221.  
  222. // A help menu that is displayed once, and again whenever
  223. // the user enters h or H
  224. void help()
  225. {
  226.     cout << "Instructions for listed commands:\n"
  227.          << "T: Display the total number of lines.\n"
  228.          << "F: Print all lines.\n"
  229.          << "B: Print all lines in reverse order.\n"
  230.          << "I <line number> <text>: Insert a new line with text\n"
  231.          << "   \"<text>\" at line number \"<line number>\".\n"
  232.          << "L <line number 1> <line number 2>: List lines \n"
  233.          << "   \"<line number 1>\" through lines \"<line number 2>.\"\n"
  234.          << "D <line number 1> <line number 2>: Delete lines \n"
  235.          << "   \"<line number 1>\" through lines \"<line number 2>.\"\n"
  236.          << "S <output file name>: Save the current file under a new name.\n"
  237.          << "H: Display this help menu.\n"
  238.          << "A: Display information about the developer.\n"
  239.          << "Q: Quit editing the file (without saving it).\n";
  240.     return;
  241. }
  242.  
  243. // fillList searches for a file called "input.txt" and then
  244. // reads from it, inserting lines one at a time into nodes
  245. // in the linked list.
  246. bool fillList(LinkedList<string> *list)
  247. {
  248.     string line;                //this string will take input from the file
  249.     ifstream fIn;               //create an ifstream object
  250.     fIn.open("input.txt");      //open it
  251.     if(!fIn.is_open())          //check to see if the file is open, if not, exiting
  252.     {
  253.         cout << "File not found. Ending program.\n";
  254.         return 0;
  255.     }
  256.  
  257.     while(!fIn.eof())
  258.     {
  259.         getline(fIn, line);
  260.         line.append(1, '\n');
  261.         list->insertNode(line);
  262.         line.clear();
  263.     }
  264.     fIn.close();
  265.     return true;
  266. }
  267.  
  268. /// THIS IS THE CLASS FILE YOU NEED TO CUT AND PASTE THIS FROM HERE TO THE END, INTO A NEW FILE.
  269. /// AND YOU NEED TO MAKE A PROJECT AND INCLUDE THIS FILE. IF YOU DON'T KNOW HOW TO BUILD A PROJECT
  270. /// USING YOUR IDE, GOOD F*CKING LUCK
  271.  
  272. // A class template for holding a linked list.
  273. // The node type is also a class template.
  274.  
  275. #ifndef CIRCULARLYDOUBLYLINKEDLIST_H
  276. #define CIRCULARLYDOUBLYLINKEDLIST_H
  277. #include <iomanip>
  278. #include <fstream>
  279.  
  280. //*********************************************
  281. // The ListNode class creates a type used to  *
  282. // store a node of the linked list.           *
  283. //*********************************************
  284.  
  285. template <class T>
  286. class ListNode
  287. {
  288. public:
  289.     T value;           // Node value
  290.     ListNode<T> *next; // Pointer to the next node
  291.     ListNode<T> *prev; // Pointer to the previous node
  292.  
  293.     // Constructor
  294.     ListNode (T nodeValue){ value = nodeValue; next = NULL; prev = NULL; }
  295. };
  296. //*********************************************
  297. // The SentinelNode class creates a type used to
  298. // point to the dummy node in the
  299. // linked list, and the number of elements.
  300. //*********************************************
  301. template <class T>
  302. class SentinelNode
  303. {
  304. public:
  305.     ListNode<T> *head;   // List head pointer
  306.     ListNode<T> *prev; // Pointer to the end of the list
  307.     int count;           // Number of ListNodes in the Linked List
  308.     SentinelNode() { head = prev = new ListNode<T>("Dummy Node"); count = 0; } // Constructor
  309. };
  310. //*********************************************
  311. // LinkedList class                           *
  312. //*********************************************
  313.  
  314. template <class T>
  315. class LinkedList
  316. {
  317. private:
  318.     SentinelNode<T> *sentPtr; // Pointer to the sentinel node
  319. public:
  320.     // Constructor
  321.     LinkedList(){ sentPtr = new SentinelNode<T>; sentPtr->head->next = sentPtr->head->prev = sentPtr->head; }
  322.  
  323.    // Destructor
  324.    ~LinkedList();
  325.  
  326.    // Linked list operations
  327.    int getCount() {return sentPtr->count;}
  328.    void insertNode(T, int lineNumber = 0); // LineNumber is an optional parameter
  329.    void deleteNode(int);
  330.    void saveText(std::string);
  331.    // search
  332.    // other linked list operations ...
  333.    // ...
  334.    void displayLine(int lineNo) const;
  335.    void displayList() const;
  336.    void displayListReversed() const;
  337. };
  338.  
  339. // savetext is similar to the display function, but instead of sending output
  340. // to the console, it sends the linked list to a file.
  341. template <class T>
  342. void LinkedList<T>::saveText(std::string name)
  343. {
  344.     std::ofstream out;
  345.     out.open(name.c_str());
  346.     ListNode<T> *nodePtr;  // To move through the list
  347.  
  348.     // Position nodePtr at the head of the list.
  349.     nodePtr = sentPtr->head->next;
  350.  
  351.     // While nodePtr points to a node, traverse
  352.     // the list.
  353.     int counter = 1; // Counter will be used to show the line numbers
  354.     while (nodePtr != sentPtr->head)
  355.     {
  356.         out << nodePtr->value;  // Display the value in this node.
  357.         nodePtr = nodePtr->next;         // Move to the next node.
  358.         counter++;
  359.     }
  360.     out.close();
  361.     return;
  362. }
  363. //*********************************************
  364. // deleteNode walks to a node and deletes it.
  365. // deleteNode works for both the previous and next
  366. // pointers.
  367. //*********************************************
  368. template <class T>
  369. void LinkedList<T>::deleteNode(int lineNumber)
  370. {
  371.    ListNode<T> *nodePtr;       // To traverse the list
  372.    ListNode<T> *previousNode;  // To point to the previous node
  373.  
  374.    // Initialize nodePtr to 1st non-dummy node in the list
  375.    nodePtr = sentPtr->head->next;
  376.    previousNode = sentPtr->head; // Point previousNode to the dummy node in the list
  377.  
  378.    // Walk to the line to be deleted
  379.    for (int i = 1; i < lineNumber; i++)
  380.    {
  381.       previousNode = nodePtr;
  382.       nodePtr = nodePtr->next;
  383.    }
  384.  
  385.    // If node-to-delete not found OR no nodes; I don't want to delete the head node!!!
  386.    if (nodePtr == sentPtr->head)
  387.       return;
  388.  
  389.    // Determine if the first node is the one. Will always be true when lineNumber == 1
  390.    if (previousNode == sentPtr->head)
  391.    {
  392.       nodePtr = nodePtr->next;
  393.       delete sentPtr->head->next;
  394.       sentPtr->head->next = nodePtr; // make the dummy node point to the 2nd node in the list. Similar to sentPtr->head->next->next, only the program crashes if I put that instead.
  395.       sentPtr->head->next->prev = previousNode; // Make the new 1st node in the list point backwards to the dummy node.
  396.    }
  397.    else
  398.    {
  399.       // otherwise (node-to-delete found & not first node)
  400.       previousNode->next = nodePtr->next;
  401.       nodePtr->next->prev = previousNode;
  402.       delete nodePtr;
  403.    }
  404.    sentPtr->count--;
  405.    return;
  406. }
  407.  
  408. //**************************************************
  409. // The insertNode function inserts a node with     *
  410. // newValue copied to its value member.            *
  411. //**************************************************
  412.  
  413. template <class T>
  414. void LinkedList<T>::insertNode(T newValue, int lineNumber)
  415. {
  416.     ListNode<T> *newNode;             // A new node
  417.     ListNode<T> *nodePtr;             // To traverse the list
  418.     ListNode<T> *previousNode = sentPtr->head; // The previous node
  419.  
  420.     newNode = new ListNode<T>(newValue);            // Allocate a new node and store newValue there.
  421.     newNode->next = newNode->prev = sentPtr->head;  // Point the newNode's head and prev to the dummy node
  422.  
  423.     nodePtr = sentPtr->head->next;                  // Position nodePtr at the head of list.
  424.  
  425.     // Skip all nodes whose value is less than newValue.
  426.     if(!lineNumber)
  427.         while (nodePtr != sentPtr->head)//sentPtr->head)
  428.         {
  429.             previousNode = nodePtr;
  430.             nodePtr = nodePtr->next;
  431.         }
  432.     else
  433.         for (int i = 1; i < lineNumber; i++)
  434.         {
  435.             previousNode = nodePtr;
  436.             nodePtr = nodePtr->next;
  437.         }
  438.  
  439.     // If the new node is to be the 1st in the list,
  440.     // insert it before all other nodes.
  441.     if (previousNode == sentPtr->head)//sentPtr->head)
  442.     {
  443.         sentPtr->head->next = newNode;
  444.         newNode->prev = sentPtr->head; // Make the first non-dummy node in the list point backwards to the dummy node.
  445.     }
  446.     else  // Otherwise insert after the previous node.
  447.     {
  448.         previousNode->next = newNode;
  449.         newNode->prev = previousNode; // Make the new node point backwards to the previous node.
  450.     }
  451.  
  452.     if (newNode->next == sentPtr->head) // If the node points forward to the dummy node, then the dummy node should point backwards to this new node.
  453.         sentPtr->head->prev = newNode;
  454.  
  455.     newNode->next = nodePtr;
  456.     sentPtr->count++;
  457. }
  458.  
  459. //**************************************************
  460. // displayList shows the value stored in each node *
  461. // of the linked list pointed to by head.          *
  462. //**************************************************
  463.  
  464. template <class T>
  465. void LinkedList<T>::displayList() const
  466. {
  467.     ListNode<T> *nodePtr;  // To move through the list
  468.  
  469.     // Position nodePtr at the head of the list.
  470.     nodePtr = sentPtr->head->next;
  471.  
  472.     // While nodePtr points to a node, traverse
  473.     // the list.
  474.     int counter = 1; // Counter will be used to show the line numbers
  475.     while (nodePtr != sentPtr->head)
  476.     {
  477.         std::cout << std::setw(2) << std::left << counter << std::right << " " << nodePtr->value;  // Display the value in this node.
  478.         nodePtr = nodePtr->next;         // Move to the next node.
  479.         counter++;
  480.     }
  481.     return;
  482. }
  483. //**************************************************
  484. // displayList shows the value stored in each node *
  485. // of the linked list pointed to by head... IN REVERSE!!!!
  486. //**************************************************
  487.  
  488. template <class T>
  489. void LinkedList<T>::displayListReversed() const
  490. {
  491.     ListNode<T> *nodePtr;  // To move through the list
  492.  
  493.     // Position nodePtr at the rear of the list.
  494.     nodePtr = sentPtr->head->prev;
  495.  
  496.     // While nodePtr points to a node, traverse
  497.     // the list.
  498.     int counter = 1; // Counter will be used to show the line numbers
  499.     while (nodePtr != sentPtr->head)
  500.     {
  501.         std::cout << std::setw(2) << std::left << counter << std::right << " " << nodePtr->value;  // Display the value in this node.
  502.         nodePtr = nodePtr->prev;         // Move to the next node. IN REVERSE!!!
  503.         counter++;
  504.     }
  505.     return;
  506. }
  507. // displayLine takes an int and walks through the linked list to
  508. // the corresponding node number, then displays that node's value.
  509. template <class T>
  510. void LinkedList<T>::displayLine(int lineNo) const
  511. {
  512.     ListNode<T> *nodePtr = sentPtr->head->next; // Initialize nodePtr to point to the first non-dummy node.
  513.     int counter; // I declared counter outside of the for-loop so that the cout statement could access counter.
  514.     for (counter = 1; counter < lineNo; counter++) // Counter will be used to walk through the linked list
  515.         nodePtr = nodePtr->next;
  516.     std::cout << std::setw(2) << std::left << counter << std::right << " " << nodePtr->value;  // Display the value in this node.
  517.  
  518.     return;
  519. }
  520. //**************************************************
  521. // Destructor                                      *
  522. // This function deletes every node in the list.   *
  523. //**************************************************
  524.  
  525. template <class T>
  526. LinkedList<T>::~LinkedList()
  527. {
  528.    ListNode<T> *nodePtr;   // To traverse the list
  529.    ListNode<T> *nextNode;  // To point to the next node
  530.  
  531.    // Position nodePtr at the head of the list.
  532.    nodePtr = sentPtr->head->next;
  533.  
  534.    // While nodePtr is not at the end of the list...
  535.    while (nodePtr != sentPtr->head)
  536.    {
  537.       // Save a pointer to the next node.
  538.       nextNode = nodePtr->next;
  539.  
  540.       // Delete the current node.
  541.       delete nodePtr;
  542.  
  543.       // Position nodePtr at the next node.
  544.       nodePtr = nextNode;
  545.    }
  546.    delete sentPtr->head;
  547.    delete sentPtr;
  548. }
  549. #endif
Advertisement
Add Comment
Please, Sign In to add comment