I have an exercise like this:

Design a simple text editor in console mode, not window form
max character in a line is 80
user can move cursor up, down, to left and right, insert, delete character

I don't know how to build it :(
i should use linked list or stack? and how to move the cursor, and ... lots of things i don't know

some one please help me!

Recommended Answers

All 15 Replies

Not possible to do it in pure C or c++ because the languages do not support cursor movement. You could do it in MS-DOS pretty easily with TurboC++ compiler. All modern MS-Windows compilers will require win32 api console functions. For *nix I suppose you might have to use curses library functions.

you could use a 3d array of characters?

interfacing with the console
If on Windows you'll have to use the (non-standard) stuff in <conio.h>. Just include the library file and compile.

If on linux you'll have to use the curses library. There are various versions of it: curses, ncurses, and pdcurses. You are sure to have at least one of them. To compile a program using the curses library you need to do something like: g++ -o myprog myprog.cpp -lpdcurses (assuming "pdcurses", of course). If you have more than one version of curses, choose pdcurses over ncurses over curses... In all cases, include the file <curses.h> in your code. Get documentation on the internet, or at the school terminal prompt by typing "man curses".

Don't try to get around curses. Raw input from the keyboard is not always friendly. The curses library makes it friendly.

memory layout
There are two common ways to store textual data. I recommend you stick with a linked list of lines. That is how vi does it. (The other method is to have the entire file stored in one giant buffer, and the stuff on screen copied over into a smaller editing buffer. This is how emacs does it. There is nothing wrong with this method, but it requires some careful bookkeeping you can avoid for a simple assignment.)

example
Here is a simple example for you:

#include <curses.h>

int main() {
  // Initialize the curses library
  initscr();
  raw();
  (void) noecho();
  nonl();
  intrflush( stdscr, FALSE );
  (void) keypad( stdscr, TRUE );

  // make sure the cursor is visible
  curs_set( 1 );

  // clear the screen
  wclear( stdscr );

  // move the cursor to (x, y) = (10, 5)
  wmove( stdscr, 5, 10 );

  // insert characters (instead of waddstr())
  winsstr( stdscr, "Press the 'Any' key" );

  // update
  wrefresh( stdscr );

  // wait for user to press a single key
  wgetch( stdscr );

  // all done
  endwin();
  return EXIT_SUCCESS;
  }

For an editor, you will usually want to use winstr() to insert characters in a line instead of waddstr() which overwrites...

Other useful functions are: wdelch(), winsdelln(), getyx(), and winsch().

Well, that should be enough to get you started.

Good luck.

Member Avatar for iamthwee

Sounds like a pretty retarded exercise to me! And I bet, somehow turbo c is involved!

If you are using the (ancient, obsolete) TurboC, then you have access to functions like clrscr(), and gotoxy(). With other windows compilers, though, you are unlikely to have them... The Wikipedia article lists all the functions from conio.h you are likely to have on any given windows compiler. If you are using an MS compiler, you might have something like _clearscreen() or somesuch...

You could, like Ancient Dragon said, play with the Windows Console functions, which aren't that difficult (SetConsoleCursorPosition()), but require a bit of reading.

I still recommend using pdcurses. It is truly cross-platform and avoids having to play with callback hooks...

[EDIT]
Actually, now that I'm awake... Hasn't your professor given you any instruction on how to interface with the console? Seems an odd assignment without giving you some instructions on how to read arrow key presses and position the cursor on the screen...

Thank you very much!
I'm just a beginner in C++ so something you said I don't understand clearly.
This is my simple program, I use double linked list, the program opens a text file, and show the file's content. (I will add the cursor movement later)
My file's content:

When I see your face, I know that I'm finally yours.
I find a reason, I thought that I lost before.

But when I run the program, it shows:

Filename: 1.txt

The content:

When I see your face, I know that I'm finally yours.════════════════════════════
@¶D═I find a reason, I thought that I lost before.══════════════════════════════
═══░‼D══════════════════════════════════════════════════════════════════════════
══════Press any key to continue

Please show me what my mistake is!
Thanks you very much!!!
P/S: I'm not good at English :(

#include <iostream.h>
#include <fstream.h>
#include <assert.h>

typedef struct Node
{
	char character[80];
	Node *next, *pre;
}Line;

Line *currentline;
Line *firstline;
Node *head, *tail;
int col;

void createfirstline()
{
	Node *p;
	p = new Node;
	currentline = p;
	head = currentline;
	tail = currentline;
	col = -1;
}

void newline()
{
	Node *p;
	p = new Node;	
	p -> next = NULL;
	p->pre = currentline;
	currentline->next = p;
	tail = p;
	currentline=p;
	col = 0;
}


void createnewline(char x)
{
	Node *p;
	p = new Node;		
	p -> next = NULL;
	if (head == NULL)
	{
		head = p;
		tail = p;
	}
	else
	{
		Node *q = tail;
		q->next = p;
		p->pre = q;		
	}
	tail = p;
	currentline = p;
}

void readfile()
{
	Node *p;
	p = head;
	if (head == NULL)
		cout << "\nFile is empty!\n" << endl;
	else
	{
		cout << "\nThe content: " << endl << endl;
		while (p != NULL)
		{
			cout << p->character;				
			p = p->next;
		}
	}
}

void main()
{
	cout << "Filename: ";
	char filename[30];
	cin.getline (filename,30);

	ifstream instream;
	instream.open(filename,ios::nocreate);
	if (!instream)
	{
		cout << "Cannot open the file\n";
	}
	else
	{		
		char reading;
		currentline = firstline;
		createfirstline();
		while(instream.read(&reading,sizeof(reading)))
		{
			if (reading == '\n')
				newline();
			else
			{
				col++;
				currentline->character[col] = reading;
			}
		}
		readfile();
	}
	instream.close();
}
Member Avatar for iamthwee

Honey why don't you tell us what you're using. Is is turbo c?

You did not null-terminate the string. After line 102 (end of the loop) add this: currentline->character[col] = 0; Or, even easier, use a std::string object for file input and getline() to read every line in the file. If you do that then you don't need to read the file one character at a time or worry about the '\n' character because getline() will do that for you.

std::string reading;
while( getline(instream, reading) )
{
     strcpy( currentline->character, reading.c_str());
}

What is readfile on line 59 supposed to do? Did you name that function correctly? As currently written all it does is diaplay the text that was read from main().

With the kind of syntax errors it is letting him get away with it almost undoubtedly is TurboC...

Don't use C style headers. Use instead C++ headers. #include <iostream> #include <fstream> #include <cassert> Personally, I can't stand all the assert stuff people throw in their code for minor errors... but seeing as you don't use any you don't need to include the header...

The main() function always returns an int. At the very least it should look like this:

int main()
{
  // do stuff here
  return EXIT_SUCCESS;
}

The ifstream class does not need to be told not to create a file. (But ios::nocreate is non-standard anyway.) Just say: instream.open( filename ); OK, on to logic errors.
First, you need to be much more careful how you handle your linked list nodes. You've got dangling pointers.

Use function arguments to create a node, not global variables. This will help fix your errors. For example, create a function named: Line *add_node( char *text, Line *prev, Line *next ); All this function should do is create a new node and fill it with the information given to it.
This forces you to separate your linked list code from handling global variables. To create the first node in the list, just say head = tail = add_node( "I am first", NULL, NULL ); You can append a node in a similar way: tail = add_node( "I am not first", tail->prev, NULL ); The reason your output is full of funny characters is because you have not initialized your char[80] string properly. This is because you are reading until you get to the end of line but otherwise not terminating your string or clearing it of characters already there. A slight "animation", as it were:

xy--ze===gobbledegook...ze   (line as it is when you start the program)
[B]W[/B]y--ze===gobbledegook...ze
[B]Wh[/B]--ze===gobbledegook...ze
[B]Whe[/B]-ze===gobbledegook...ze
[B]When[/B]ze===gobbledegook...ze
[B]When [/B]e===gobbledegook...ze
[B]When I[/B]===gobbledegook...ze
[B]When I [/B]==gobbledegook...ze
[B]When I s[/B]=gobbledegook...ze
etc...

See what is happening? To read lines from file, instead use something like:

char reading[ 80 ];
instream.getline( reading, 80 );

This will read a maximum of 79 characters into a reading string and guarantee that it is null-terminated. You can then copy this string into a node using add_node().

Hope this helps.

Thank you very much!
This problem is solved. I can display the content of the file.
I use this function to move the cursor:

void gotoxy(int x, int y) 
{
	COORD coord; 
	coord.X = x; 
	coord.Y = y; 
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); 
}

And these lines in my main() (it's only a demo):

char input;
		do
		{
			input = getch();
			switch (input)
			{
			case 72:	//Up
				row--;
				continue;
			case 80:	//Down
				row++;
				continue;
			case 77:	//Right
				col++;
				continue;
			case 75:	//Left 
				col--;
				continue;
			}
			gotoxy(col,row);
		}
		while (input != 13); //Enter to save
	}

Yah, now I can move the cursor, but sometimes it doesn't move for a while.

My next big question now is how edit the line where the cursor is in. I only can add new characters behind the old one and save this line.

I'm using Microsoft Visual C++ 6.0.

Thank you again, you are my saviour!

P/S: how to add lines number in code when we post?

you need another counter that keeps track of where in the line the cursor is located and increment or decrement it at the same time that you change the col counter.

Also, when moving the left arrow you need to check that col is greater than zero to prevent negative values. And same with the counter I mentioned above.

>>I'm using Microsoft Visual C++ 6.0.
Unless you have to use it for school you should just trash that compiler and get VC++ 2005 Express (and the current Windows SDK). VC++ 6.0 is a very old compiler which does not conform to C++ standards very well.

Line numbers are added when you specify what language you are posting with.

[[I][/I]code=C++[I][/I]]
int main() { ...
[[I][/I]/code[I][/I]]

becomes

int main() { ...

Its a pain to set up express to use the plaform sdk

Its a pain to set up express to use the plaform sdk

Yes, but the instructions are pretty clear, if you follow them closely you should not experience any problems.

mmm i just use Dev C++ instead

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.