codetoad.com
  ASP Shopping CartForum & BBS
  - all for $20 from CodeToad Plus!
  
  Home || ASP | ASP.Net | C++/C# | DHTML | HTML | Java | Javascript | Perl | VB | XML || CodeToad Plus! || Forums || RAM 
Search Site:
Search Forums:
This 23 message thread spans 2 pages: [1]  2  > >  
  Lost part 2!!!  newProgrammer19 at 07:52 on Tuesday, December 05, 2006
 

coding in process.....



  Re: Lost part 2!!!  Gord T at 08:24 on Tuesday, December 05, 2006
 

This is the complete code. There are things that can be improved.
A quick run-thru and seems okay. To check for parsing issues when
I paste the code here, I'll copy it back and run a new instance of
the program. If there are errors, then it's a parsing issue that we'll
have to solve.


///////////////////////////////////////////////
//
// Lost.cpp
// New version Dec 05 3:08am 2006
// compiler Devc++
// TODO: better UI after debugging
// optimize code
//////////////////////////////////////////////
#include <cstdlib>
#include <iostream>
#include "conio.h"
#include <fstream>
using namespace std;
//..........................
#define FILE_ID "123456"
//just a couple constants to help with parsing/posting issues.
#define ZERO 0
#define NUMBER_1 1
#define NUMBER_2 2
#define SIZE_FILEPATH 160
#define SIZE_TEXT_LINE 80
#define NEW_LINE_CHAR 10

//......................
//struct cell:
// Each cell in a row is comprised of this.
// I used a fixed array to hold the string. This keeps memory management
// easier and allows porting code to write binary files instead of text files.
//
#define SIZE_CELL_DATA 64

typedef struct cell_s
{
//a character array holds string representation of number
// only chData is stored in the file
char chData[SIZE_CELL_DATA];

// for reference if needed. Not stored in file.
//Not actually read in this example.
long cell_number;
long row_number;

}cell_t;

//.......................
// struct data_base
// The header of where it begins.
//
typedef struct data_base_s
{
long num_rows;
long cells_per_row;

cell_t *cells; //all cells used in data base

}data_base_t;

//............................
//
// Prototypes
//
data_base_t * CreateDataBase(long num_rows,long cells_per_row);
void SetData(data_base_t * db,long row_num, long cell_num, char * chData);
cell_t *GetCell(data_base_t * db,long row_num, long cell_num);
void FreeDataBase(data_base_t * db);
void PrintDataToScreen(data_base_t * db);
void PrintDataToFile(data_base_t * db, char *file_path);
data_base_t * ReadDataFile(char * file_path);
long GetUserNumber();
data_base_t * PromtUserDataBaseInfo(char * file_path);
void UserSaveData(data_base_t * db, char * file_path);
void GoUserEdit(data_base_t *db);

//..........................
//
// main() or _tmain()
//
//
int main(int argc, char *argv[])
{


char file_path[SIZE_FILEPATH]; //user file path.
data_base_t *myData = (data_base_t *)ZERO; //our data base

memset(file_path,ZERO,SIZE_FILEPATH); //clear it first always.

//Get user info and alloc new data base or open existing.
myData = PromtUserDataBaseInfo(file_path);
if(!myData)
{ system("PAUSE");
return ZERO; //error or user abort
}

GoUserEdit(myData); //allow cell editing

UserSaveData(myData,file_path); //allow saving file

FreeDataBase(myData);
system("PAUSE");

return EXIT_SUCCESS;
}//

//................................
//
// GoUserEdit:
// Let user edit cells
// Assumes data base is valid.
//
void GoUserEdit(data_base_t *db)
{

char chUserKey;
long nRow,nCell;
cell_t *cell = (cell_t*)ZERO;
char user_data[SIZE_CELL_DATA];


cout << "Row range is 1 to " << db->num_rows << endl;
cout << "Cells per row range is 1 to " << db->cells_per_row << endl;

while(NUMBER_1) //loop forever
{
cout << endl << "To edit cells press 1, else proceed to save as." << endl;
chUserKey = _getch();
if(chUserKey != '1') return; //all done here


cout << endl << "Which row do you want to edit? (1 is first)" << endl;

while(NUMBER_1)
{
nRow = GetUserNumber();
//check range
if((nRow >= NUMBER_1) && (nRow <= db->num_rows)) break; //okay
cout << "Row value is out of range. Please try again. " << endl;

}//while row


cout << "Which cell in that row do you want to edit?(1 is first)" << endl;
while(NUMBER_1)
{
nCell = GetUserNumber();
//check range
if((nCell >= NUMBER_1) && (nCell <= db->cells_per_row)) break; //okay
cout << "Cell value is out of range. Please try again. " << endl;

}//while cell

//our values are actually +1 so decrement them for use in array.
nRow--;
nCell--;

cell = GetCell(db,nRow,nCell);
cout << "The current value for this cell is " << cell->chData << endl;
cout << "Change value? (1 = yes)...";

chUserKey = _getch();
if(chUserKey != '1') continue; // skip rest of code and loop back to top.

cout << "Enter new value...";
memset(user_data,ZERO,SIZE_CELL_DATA);
cin >> user_data;
SetData(db,nRow,nCell,user_data);

//Show what's in the file
cout << endl;
PrintDataToScreen(db);
cout << endl;

}//while root
}//

//..................
//
// UserSaveData:
//
void UserSaveData(data_base_t * db, char * file_path)
{

cout << endl << "Save file <" << file_path << "> ? (press 1)";

if(_getch() != '1')
{ cout << endl <<"File not saved." << endl;
return;
} //if

PrintDataToFile(db,file_path);

}//

//..........................
//
// PromtUserDataBaseInfo:
// This functions queries the user for information and returns a data base.
// If user selects to open an existing file, that is returned.
// If user opts to create new data base, one is allocated and returned.
// A null pointer (0) is returned if any errors.
// filepath recieves the filename user selects or names and must be
// pre-allocated.
//
data_base_t * PromtUserDataBaseInfo(char * file_path)
{
char chUserKey;
long num_rows,cells_per_row;
data_base_t * db = (data_base_t *)ZERO;

//See if user wants to open and edit a file or create a new data base.
cout << "Please choose one of the following:" << endl << endl;
cout << "Open an existing file to edit...press 1" << endl;
cout << "Create a new data base..........press 2" << endl;
cout << "Cancel............................other" << endl;
chUserKey = _getch();

if(chUserKey == '1') //open an existing file
{
cout << "Enter name of file to open..." << endl ;
cin >> file_path;

//try and read the file
db = ReadDataFile(file_path);
if(!db){return (data_base_t*)ZERO;}

//Show what's in the file
cout << endl;
PrintDataToScreen(db);
cout << endl;
}
else if (chUserKey == '2') //create new data base
{
cout << "Enter name of file to save as..." << endl ;
cin >> file_path;

//We need to know how big a data base user wants to create.
cout << "How many rows will your data base need?...";
num_rows = GetUserNumber();

cout << "How many cells per row will your data base need?...";
cells_per_row = GetUserNumber();

//Create new data base
db = CreateDataBase(num_rows,cells_per_row);

if(!db)
{
cout << "Error creating data base <" << file_path << ">" << endl;
return (data_base_t*)ZERO;
} //if
//cout << "Data base created." << db->num_rows << " rows,"
//<< db->cells_per_row << " cells per row." << endl;

cout << "Data base created." << endl;

//Show what's in the file
cout << endl;
PrintDataToScreen(db);
cout << endl;
}
else
{ cout << endl << "User aborted.";
return (data_base_t*)ZERO;
}

return db;
}//

//............................

//
// Gets a number from the user.
//
//
long GetUserNumber()
{
char temp[SIZE_TEXT_LINE];
long user_num;

memset(temp,ZERO,SIZE_TEXT_LINE);
user_num = ZERO;
while(!user_num)
{
cin >> temp;
user_num = atol(temp);
if(!user_num) cout << "invalid number,please try again..." ;
}//while

return user_num; //if we are here there were no errors.

}//

//.................................
//
// CreateDataBase:
// Creates and allocates a new data base.
// User supplies number of rows and cells per row.
// If USE_SAMPLE_DATA, cells are intialized to "(row,cell)" as example
// if it is zero then alls cells are initialized to "init"
#define USE_SAMPLE_DATA 1
data_base_t * CreateDataBase(long num_rows,long cells_per_row)
{
data_base_t *db = (data_base_t *)ZERO;
long nRow,nCell;
char buffer[SIZE_CELL_DATA];

//allocate for header
db = (data_base_t *)malloc(sizeof(data_base_t));
memset(db,ZERO,sizeof(data_base_t)); //set all bytes to zero.(habit)

db->num_rows = num_rows;
db->cells_per_row = cells_per_row;

//allocate for all of the cells we will need.
db->cells = (cell_t*)malloc(num_rows * cells_per_row * sizeof(cell_t));
memset(db->cells,ZERO,num_rows * cells_per_row * sizeof(cell_t));

//For each cell, fill in some info.
//for this example, I am going to assign row-cell number
// to the data. Like... row 1 cell 3 = (1,3)
for(nRow = ZERO; nRow < num_rows; nRow++)
{
for(nCell = ZERO; nCell < cells_per_row; nCell++)
{
#ifdef USE_SAMPLE_DATA
//example data...(row num, cell num)
memset(buffer,ZERO,SIZE_CELL_DATA);
sprintf(buffer,"(%d,%d)",nRow+NUMBER_1,nCell+NUMBER_1);
#else
// initialize all cells to "init"
memset(buffer,ZERO,SIZE_CELL_DATA);
sprintf(buffer,"init",nRow,nCell);
#endif
//set it assignes it.
SetData(db,nRow,nCell,buffer);
}//x
}//y

return db;
}//

//........................................
//
// SetData:
// Sets a string (chData) and info for a given cell.
//
void SetData(data_base_t * db,long row_num, long cell_num, char * chData)
{
cell_t * cell;

cell = GetCell(db,row_num,cell_num);

cell->row_number = row_num;
cell->cell_number = cell_num;

memset(cell->chData,ZERO,SIZE_CELL_DATA); //clear first.
strcpy(cell->chData,chData);

}//

//...................................
//
// GetData:
// returns a pointer to the cell given a row and cell number
//
cell_t *GetCell(data_base_t * db,long row_num, long cell_num)
{return &db->cells[row_num * db->cells_per_row + cell_num];
}//

//.............................
//
// PrintDataToScreen:
// Just to show what's happening.
//
void PrintDataToScreen(data_base_t * db)
{
long nRow,nCell;
cell_t *cell = (cell_t*)ZERO;

for(nRow = ZERO; nRow < db->num_rows; nRow++)
{
for(nCell = ZERO; nCell < db->cells_per_row; nCell++)
{
cell = GetCell(db,nRow,nCell);
cout << cell->chData << " ";
}
cout << endl;
}


}
//..............................................
//
// PrintDataToFile
// Prints a text file with the data.
// This will overwrite file if already exists.
//
void PrintDataToFile(data_base_t * db, char *file_path)
{

ofstream myfile (file_path); //open the file.
char new_line = NEW_LINE_CHAR; //new line character.NEED THIS.
char buffer[SIZE_TEXT_LINE];
long max_cells;


if (!myfile.is_open())
{
cout << "Error opening <" << file_path << ">" << endl;
return;
}//if

//First we need to write the ID number and start a new line.
//then number of rows,
//then number of cells per row.
//Then we can write actual string (cell) data.

//Get a string of our file ID
//write it with new-line character at end.
memset(buffer,ZERO,SIZE_TEXT_LINE); //to be sure
sprintf(buffer,"%s%c",FILE_ID,new_line);
myfile.write(buffer,(long)strlen(buffer));

//Same for rows...
memset(buffer,ZERO,SIZE_TEXT_LINE);
sprintf(buffer,"%d%c",db->num_rows,new_line);
myfile.write(buffer,(long)strlen(buffer));

//same for cells...
memset(buffer,ZERO,SIZE_TEXT_LINE);
sprintf(buffer,"%d%c",db->cells_per_row,new_line);
myfile.write(buffer,(long)strlen(buffer));

//now write each cell.
long nCell;
cell_t *cell = (cell_t*)ZERO;

max_cells = db->num_rows * db->cells_per_row;

for(nCell = ZERO; nCell < max_cells; nCell++)
{
//write the cell data.
cell = &db->cells[nCell];//just point to it.
myfile.write(cell->chData,(long)strlen(cell->chData));
//add an end of line character.
myfile.write(&new_line,NUMBER_1);

}//for

myfile.close();
cout << "OK" << endl;

}//

//..........................
//
// ReadDataFile:
// Allocates for and reads in a data base file.
// The data is stored in the cell variable chData.
// What you do with it from there is up to you.
//
data_base_t * ReadDataFile(char * file_path)
{

data_base_t *db = (data_base_t*)ZERO;
ifstream myfile (file_path); //open input stream for the file.
string line;

long num_rows, cells_per_row;

//check file open state.
if (!myfile.is_open())
{
cout << "Error opening file <" << file_path << ">" << endl;
return (data_base_t*)ZERO;
}//if

//Read first line, should be == FILE_ID
getline(myfile,line);

if(line != FILE_ID)
{
cout << "File <" << file_path << "> is not a valid data base. Exiting." << endl;
myfile.close();
return (data_base_t*)ZERO;
}

//OK,next line should be num rows, followed by cells_per_row.
getline(myfile,line);
num_rows = atol(line.data());

getline(myfile,line);
cells_per_row = atol(line.data());

//Show the results and ask abort...
cout << "Num rows = " << num_rows << ", cells_per_row = " << cells_per_row << endl;
cout << "Press c to continue, else abort...";
if(_getch() != 'c')
{
cout << "aborted." << endl;
return (data_base_t*)ZERO;
}
else
{
cout << "OK." << endl;
}

// Allocate for the data base and read in all data.
db = CreateDataBase(num_rows,cells_per_row);

if(!db)
{ myfile.close();
return db; ///bad
}

//Try and read rest of file, the data cells.
long max_cells,nCell;

max_cells = db->num_rows * db->cells_per_row;
for(nCell = ZERO; nCell < max_cells; nCell++)
{
if(myfile.eof())
{ cout << "error. reached end of file before all cells read. aborting." << endl;
FreeDataBase(db);
return (data_base_t *)ZERO;
}
getline(myfile,line); //line contains the chData.
strcpy(db->cells[nCell].chData,line.data());//copy into data base cell.
}//for

myfile.close();
cout << "File read OK." << endl;
return db;
}
//.....................................
//
// FreeDataBase:
// Frees allocated memory on cleanup.
//
void FreeDataBase(data_base_t * db)
{
try
{
if(!db) return;
free(db->cells);
free(db);
}
catch(...)
{
return;
}
}//
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx end xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

  Re: Lost part 2!!!  Gord T at 09:28 on Tuesday, December 05, 2006
 

Quick fix: There exists a condition when the user creates a data base that they may assign a negative number(Why I dont know). To fix that a quick one line code is needed but here is the whole function again.

//............................
//
// Gets a number from the user.
//
//
long GetUserNumber()
{
char temp[SIZE_TEXT_LINE];
long user_num;

memset(temp,ZERO,SIZE_TEXT_LINE);
user_num = ZERO;
while(!user_num)
{
cin >> temp;
user_num = atol(temp);
if(user_num < ZERO) user_num = ZERO;
if(!user_num) cout << "invalid number,please try again..." ;
}//while

return user_num; //if we are here there were no errors.

}//

<Added>

In function CreateDataBase()... change
sprintf(buffer,"init",nRow,nCell);
to
sprintf(buffer,"init");
That line only gets compiled if #define USE_SAMPLE_DATA is commented out so it's easy to miss.

<Added>

Just for fun...did you know by including the windows header in your program you have access to the windows API? Try adding #include <windows.h> to your source file then
put this line as the very first line in your main() function.

MessageBox(NULL,"Your Name Here\nDebug version.\nStarting program.","Lost 2-Data Base Program",MB_OK);


<Added>

New feature added....currently the cell data, chData, does't accept string spaces.
So a string like "this is a long data string" gets shortened to "this" before being saved into cell->chData.The following code add-in will allow you to have long strings as well as a switch to turn this feature on and off at compile time.

Place this line with the rest of the constants near the top of the page...

#define ALLOW_SPACES_IN_TEXT 1 //1 = allow spaces in text, 0 = don't allow.

To toggle the feature on and off, set the value to 0 or 1 and recompile the program.
Also in function GoUserEdit(), change the following last part of the function code from this...


cin >> user_data;
SetData(db,nRow,nCell,user_data);

//Show what's in the file
cout << endl;
PrintDataToScreen(db);
cout << endl;

}//while root
}//
//.........................

to this.....

cin >> user_data;
#if ALLOW_SPACES_IN_TEXT
cin.get(&user_data[strlen(user_data)],SIZE_CELL_DATA);//get rest of line
#endif
SetData(db,nRow,nCell,user_data);

//Show what's in the file
cout << endl;
PrintDataToScreen(db);
cout << endl;

}//while root
}//
//.........................


  Re: Lost part 2!!!  newProgrammer19 at 08:01 on Wednesday, December 06, 2006
 

you have done more than i even could have asked, i have learned alot from your code. however, i was wondering. If you could even more in depth with what your program is doing.That would be the best way for me to learn. thanks again

  Re: Lost part 2!!!  Gord T at 08:20 on Wednesday, December 06, 2006
 

I don't know how much c++ you already know and what you don't, so maybe if you could be somewhat more specific as to what you would like explanations of I'll be happy to answer.

  Re: Lost part 2!!!  Gord T at 11:07 on Wednesday, December 06, 2006
 

in the meantime...
Just a quick overview of the database and some c++ basics with a msdn-code link at bottom.

In general the database consists of a list of cells. This list itself has no rows or columns. It is just a
series like 0 to 100. The rows and columns that make up our database table exist only in a mathematical formula.

Say we had 4 rows of 6 cells per row
This gives us a total of 24 cells...
Total cells = number_rows * cells_per_row.
So we create an array of 24 cells.

There are no rows or columns.
It is in how we define a cell's location that gives us that ability.
The above could have...
1 row of 24 cells
24 rows of 1 cell
2 rows of 12 cells and so on. It is in how we define a cells location.

Visualizing a table, for 4rows by 6 columns...
unique_cell_location_number = current_column + (current_row_number * number_of_cells_per_row)
Or in math terms... location = x + y*width where

x is horizontal units
y is vertical units
width is the number of x's in a row before starting a new row.

Using that formula, each cell can be assigned an indivdual identity and thus location.
That is how bitmaps are structured. But rgb pixel data instead of cell text data.

Defining the database and accessing it is like this

//////////////////////////////////////////////
//
// sample code
//

#define MAX_TEXT 80 //compiler replaces all occurances of this word with 80
typedef struct cell_s
{
char text[MAX_TEXT ];
}cell_t;

long num_rows = 4;
long cells_per_row = 6;
long max_cells = num_rows * cells_per_row ;//= 24 cells

//create an array of cells...

cell_t *cells = NULL;

cells = (cell_t*)malloc(max_cells * sizeof(cell_t));//allocate
memset(cells,0,max_cells * sizeof(cell_t)); //initialize all bytes to zero


//create a pointer to a cell to make code easier to handle...
cell_t *lpCell;

//the cell we want to locate
long current_row, current_column;
long location_number;


//rows & columns begin at 0, so if current_row = 3, it is technically row 4.
current_row = 3; //assumes values begin at zero (possible confusion)
current_column = 4;

//get unique location refernce number for this cell...
location_number = current_column + (current_row * cells_per_row);//brackets not needed.
// or
//location_number = x + (y * width);


//point to this cell
lpCell = &cells[ location_number]; //& is address of operator
//or
char * text;
text = cells[ location_number].text;
//or
text = lpCell->text;
//or
text = &cells[ location_number].text[0];


//since text now points to the text of the cell were editing
//we can edit that data...

memset(text,0,MAX_TEXT ); //set all bytes to zero.
strcpy(text,"This is cell data.");

cout << text << endl;
cout << lpCell->text << endl;//same

//free the memory
free(cells);

system("PAUSE");

//
// end of code
//
////////////////////////////////////


In Lost.cpp,main() has three main routines.

1/ Find out what user wants to do and return an allocated
database based on those decisions.

2/ Take the user to a place where he can edit the cells of that database.


3/ Gives the user an option to save the db to a file.


/////////////////////////////

The more specific any questions are the better.
For any deep quesions about native c++ functions like cout or printf
you can try this microsft msdn link...

http://msdn2.microsoft.com/en-us/visualc/aa336451.aspx

...and type in the search bar, cout, printf or whatever.

I'd be happy to try and answer any questions either way.

There's still alot of things that can be done with it.
Improve the UI, optimize repetitive routines, put reusable code
into a seperate source file and later put those into a library,
make re-opened databases resizable, port to binary file handling and on it goes...

Maybe you can begin breaking the three main routines into smaller functions.
One thing you could do is rewrite GetUserNumber() so that it only returns a number
that falls within a given range.

anyhooo....






  Re: Lost part 2!!!  Gord T at 12:36 on Wednesday, December 06, 2006
 

A quick(?) overview of the database file format and that'll be it till I'm asked.

The file format that is saved by this program is just a standard text file that can
be opened with any text editor like notepad.

The first line

is not really a number, just text. The program checks for this text first to see if
this file was written by our program. If not, it could be a letter to your grandma and
our program would get confused trying to read it, and hopefully abort with a nice message.
The value of this text is defined by...
#define FILE_ID "123456"
found near the top of the source code page.
This means that all files written by our program begin with the text 123456.
If this is not the first line when our prog. opens the file, we ignore it.
You can change this to any text you want as long as there are NO spaces.
If fact, try changing the source code value to
#define FILE_ID "LOST_2_DBASE"
Run the program, create a new db and save it. Close prog and open file with notepad.
First line will be: LOST_2_DBASE
Doing that though means ofcourse you can't edit previous files(with prog) you saved with a different ID.
So I guess it's kind of like a password.

The 2nd and 3rd line

Our prog. doesn't know yet how many rows or columns the db has yet so before we can read
the cell data, we have to know that. thus
2nd line is how many rows there are.
3rd line is how many cells per row there are.
After we read those, we calculate how many cells there should be, rows*cells_per_row and
allocate a db for that size.

4th line

right after above, is where the cells begin.
Each line is a seperate cell, beginning from row0 cell0.
All cells are printed sequentially beginning with row 0,all cells in that row, next row-repeaet.
Each line of text must be terminated with binary 10,which is character '\n'
which creates a new line.


Here are the contents of a db file (.txt) that I created when testing come code.
.....................
123456
3
4
(1,1)
(1,2)
(1,3)
this is a long cell
(2,1)
(2,2)
(2,3)
(2,4)
(3,1)
(3,2)
(3,3)
(3,4)
..........................
Looking at the contents...
The id or file password is: 123456
There are 3 rows.
There are 4 cells per row. Therefore 12 cells in total.
All of the cell data contain initialized data that the program sets when a new db is created,
except for the data right after cell row1,cell3
That cell contains the text "this is a long cell"
It is held in row 1, cell 4.

















  Re: Lost part 2!!!  newProgrammer19 at 03:46 on Friday, December 08, 2006
 

what was the include directy conio.h? i have never seen that before

  Re: Lost part 2!!!  vector at 10:01 on Friday, December 08, 2006
 

It's a compiler specific header. You need not worry about it.

  Re: Lost part 2!!!  Gord T at 19:44 on Friday, December 08, 2006
 

How are U making out. Did not mean to overkill the project. I just can't type in my idea's fast enough lol.

If all U need is fixed 5*5 array, maybe we can redo a much simpler project together, now that U have new understanding. Don't know, ur pretty quiet....?

  Re: Lost part 2!!!  newProgrammer19 at 08:16 on Saturday, December 09, 2006
 

no what you have done, is awesome. i could have asked for more. you have no idea the help you have been. i working in a encryption project, if you would like to help me with this one that would be awesome.

  Re: Lost part 2!!!  Gord T at 16:55 on Saturday, December 09, 2006
 

Sure, if it's not too big, maybe post something when your ready. Maybe this time I will just offer suggestions if I have any.

  Re: Lost part 2!!!  newProgrammer19 at 20:20 on Saturday, December 09, 2006
 

also here is the cpp file.

#include "CinReader.h"

CinReader::CinReader ()
{
}

CinReader::~CinReader ()
{
}

int CinReader::readInt (bool userLimit, int lower, int upper)
{
string input = "";
string msg = "";
getline (cin, input);
input = stripCommas(input);
if (userLimit)
{
while (!testIntInput(input, msg, lower, upper))
{
cout << "ERROR: " << msg << "\n";
cout << "Reenter number [" << lower << " to " << upper << "] ";
getline (cin, input);
}
}
else
{
while (!testIntInput(input, msg))
{
cout << "ERROR: " << msg << "\n";
cout << "Reenter: ";
getline (cin, input);
}
}

return (atoi(input.c_str()));
}

double CinReader::readDouble ()
{
string input = "";
getline(cin, input);
input = stripCommas(input);
while (!testDoubleInput(input))
{
cout << "Input is not a double\n";
cout << "Reenter: ";
getline(cin, input);
}

return (atof(input.c_str()));
}

float CinReader::readFloat ()
{
string input = "";
getline(cin, input);
input = stripCommas(input);
while (!testDoubleInput(input))
{
cout << "Input is not a float\n";
cout << "Reenter: ";
getline(cin, input);
}

return (static_cast<float>(atof(input.c_str())));
}

char CinReader::readChar (string range)
{
bool valid = false;
string input = "";
getline(cin, input);

if (range.length() > 0)
{
do
{
while (input.length() != 1)
{
cout << "Please enter a single character: ";
getline(cin, input);
}
if (!testCharInput(input[0], range))
{
cout << "\"" << input[0] << "\" is not valid.\n";
input = "";
}
else
valid = true;
} while (!valid);
}
else
{
while (input.length() != 1)
{
cout << "Please enter a single character: ";
getline(cin, input);
}
}

return (input[0]);
}

bool CinReader::readBool ()
{
string input = "";
getline(cin, input);
while (!testBoolInput(input))
{
cout << "Please enter \"true\" or \"false\": ";
getline(cin, input);
}

return (getBoolValue(input));
}

string CinReader::readString (bool allowEmpty, unsigned int limitTo)
{
string input = "";
getline(cin, input);
if (!allowEmpty)
{
while (input.length() == 0)
{
cout << "Input cannot be blank--enter text: ";
getline(cin, input);
}
}
if (limitTo > 0)
{
if (input.length() > limitTo)
input = input.substr(0, limitTo);
}
return input;
}

string CinReader::stripCommas (string input)
{
string outs = "";
for (unsigned int i=0; i<input.length(); i++)
{
if (input != ',')
outs += input;
}
return outs;
}

bool CinReader::testIntInput (string input, string& msg, int lowerLimit, int upperLimit)
{
int upperMarker = -1;
int lowerMarker = -1;
if (upperLimit == -1)
{
upperLimit = INT_MAX;
upperMarker = 47;
}
if (lowerLimit == -1)
{
lowerLimit = INT_MIN;
lowerMarker = 48;
}

long linput = strtol(input.c_str(), NULL, 10);
stringstream ssinput;
ssinput << linput;
if (ssinput.str() != input)
{
msg = "integer input out-of-range";
return false;
}

else
{
if (input.length() > 0)
{
if (input[0] != '-' && (!isdigit(input[0])))
{
msg = "not an integer";
return false;
}
for (unsigned int i=1; i<input.length(); i++)
{
if (!isdigit(input))
{
msg = "not an integer";
return false;
}
}

int tmp = strtol(input.c_str(), NULL, 10);
if (tmp >= upperLimit)
{
if (upperMarker != -1)
{
string ts = "";
ts += input[input.length()-2];
ts += input[input.length()-1];
int ti = atoi(ts.c_str());
if (ti > upperMarker)
{
msg = "larger than 32-bit integer";
return false;
}
else
return true;
}
else
{
if (tmp == upperLimit)
return true;
else
{
msg = "larger than upper limit";
return false;
}
}
}
else if (tmp <= lowerLimit)
{
if (lowerMarker != -1)
{
string ts = "";
ts += input[input.length()-2];
ts += input[input.length()-1];
int ti = atoi(ts.c_str());
if (ti > lowerMarker)
{
msg = "smaller than 32-bit integer";
return false;
}
else
return true;
}
else
{
if (tmp == lowerLimit)
return true;
else
{
msg = "smaller than lower limit";
return false;
}
}
}
else
return true;
}
msg = "no input";
return false;
}
}

bool CinReader::testDoubleInput (string input)
{
int dotCount = 0;
if (input.length() > 0)
{
if (input[0] != '-' && (!isdigit(input[0])) && input[0] != '.')
return false;
if (input[0] == '.')
dotCount = 1;
for (unsigned int i=1; i<input.length(); i++)
{
if (input == '.')
{
if (dotCount != 0)
return false;
else
++dotCount;
}
else if (!isdigit(input))
return false;
}

return true;
}

return false;
}

bool CinReader::testCharInput (char c, string range)
{
bool valid = false;
for (unsigned int i=0; i<range.length(); i++)
{
if (range == c)
{
valid = true;
break;
}
}
return valid;
}

bool CinReader::testBoolInput (string input)
{
if (input.length() > 0)
{
if (input.length() == 1)
{
if (toupper(input[0]) == 'T' || toupper(input[0]) == 'F')
return true;
else
return false;
}
else
{
if (ignoreCaseCompare(input, "TRUE") ||
ignoreCaseCompare(input, "FALSE"))
return true;
else
return false;
}
}
else
return false;
}

bool CinReader::getBoolValue (string input)
{
if (toupper(input[0]) == 'T')
return true;
else
return false;
}

bool CinReader::ignoreCaseCompare (string input, string comp)
{
toUpperCase(input);
if (input == comp)
return true;
else
return false;
}

void CinReader::toUpperCase (string& s)
{
transform(s.begin(), s.end(), s.begin(), ::toupper);
}




  Re: Lost part 2!!!  newProgrammer19 at 20:20 on Saturday, December 09, 2006
 

ok here is the deal, i want you to look at this and see how we can add this to the last project. it replaces all the cin with ex. reader.readString(); i want to replace them with this. here is the header file. let me know how we go about that.

#ifndef CIN_READER_H_
#define CIN_READER_H_

#include <iostream>
#include <string>
#include <algorithm>
#include <climits>
#include <sstream>

using namespace std;

/**
* A class for handling keyboard input. CinReader provides
* functions for reading all of the C++ primitive data types
* and C++ strings, and performs error checking on the input.
*/
class CinReader
{
public:

/**
* Constructor.
* CinReader has no data members. The default constructor
* is provided to reinforce OO ideas and practices.
*/
CinReader ();

/**
* Destructor.
* CinReader performs no dynamic memory allocation. Destructor
* is provided for thoroughness and to reinforce good OO/C++
* programming practices.
*/
~CinReader ();

/**
* Read integer input from the keyboard.
* Used with no arguments, the function will return an integer between
* INT_MIN and INT_MAX. Optionally the function can be called
* with user-specified upper and lower limits.
* @param ul if true, limit keyboard input to user-specified range
* @param l if provided, sets the lower limit of the input
* @param u if provided, sets the upper limit of the input
* @return an integer between INT_MIN and INT_MAX if called with
* no arguments, or between l and u
*/
int readInt (bool ul=false, int l=-1, int u=-1);

/**
* Read double input from the keyboard.
* Unlike readInt, this function does not limit the range of the
* input value.
* @return a double
*/
double readDouble ();

/**
* Read float input from the keyboard.
* Unlike readInt, this function does not limit the range of the
* input value.
* @return a float
*/
float readFloat ();

/**
* Read input from the keyboard as a boolean value.
* Will accept "T", "F" or "TRUE", "FALSE" as input and will
* return a corresponding boolean value. The function is NOT
* case sensitive, it will accept input as any combination of
* uppercase and lowercase characters.
* @return a bool
*/
bool readBool ();

/**
* Read char input from the keyboard.
* Used with no arguments, the function will return the char entered at
* the keyboard. Optionally, a range of acceptable inputs can
* be specified. The range must be written as a list of chars, such as
* "abcdef".
* @param range the range of acceptable inputs
* @return a char that is a member of range if specified, or
* any single char if no range is provided
*/
char readChar (string range="");

/**
* Read string input from the keyboard.
* Used with no arguments, the function will return the string
* entered at the keyboard, which can include an empty string.
* @param allowEmpty if true, allow empty string as input, else
* require at least one character of input
* @param limitTo if 0, do not limit the number of characters of
* input; if not 0, return only "limitTo" number of
* characters
* @return a string
*/
string readString (bool allowEmpty = true, unsigned int limitTo = 0);

private:

string stripCommas (string input);
bool testIntInput (string, string&, int l=-1, int u=-1);
bool testDoubleInput (string);
bool testCharInput (char, string);
bool testBoolInput (string);
bool getBoolValue (string);
void toUpperCase (string&);
bool ignoreCaseCompare (string, string);
};

#endif


  Re: Lost part 2!!!  Gord T at 13:46 on Sunday, December 10, 2006
 

There are several ways...
First, let's look at the realationship between chData and a string.
Not sure if U want to replace 'char *chData;' with a string in the struct.
For now, let's assume not, until we solve the basic question...

For now, ignore all the the data types return by the class except string. That is what we are
currently dealing with in chData.

//sample
string myString;
CinReader reader;

myString = reader.readString(false,SIZE_CELL_DATA);

//to get the string into chData you strcpy like this...


cell_t myCell;
memset(myCell.chData,0,SIZE_CELL_DATA);
strcpy(myCell.chData,(char*)myString.data());

/////////////////////////////
//That could be put into a function to transfer string to chData line like this
//
// example
//

void StringToData(cell_t *lpCell,string str)
{
memset(lpCell->chData,0,SIZE_CELL_DATA);
strcpy(lpCell->chData,(char*)str.data());
}



void main()
{
cell_t myCell;
string myString;

//myString = "123456"; // or
myString = reader.readString(false,SIZE_CELL_DATA);

StringToData(&myCell,myString);
cout << myCell.chData << endl;

}//
//
//
// you can also do this....
void main()
{
cell_t myCell;

//combining both functions

StringToData(&myCell,reader.readString(false,SIZE_CELL_DATA));
cout << myCell.chData << endl;

}

//
//
// You can also point to the string like you do with a character array
// and use it in the same way...

char * lpChar = NULL;

lpChar = myCell.chData; //is ok
lpChar = (char*)(myString.data());//is ok




<Added>

/////////////////////////////////
in GetUserData()...

char user_data[SIZE_CELL_DATA];

cin is used liked this...
cin >> user_data;
cin.get(&user_data[strlen(user_data)],SIZE_CELL_DATA);//get rest of line
SetData(db,nRow,nCell,user_data);

instead you could...

string strUserData;

strUserData = reader.readString(false,SIZE_CELL_DATA);
SetData(db,nRow,nCell,(char*)strUserData.data() );

<Added>

I meant GoUserEdit(), not GetUserData() :)

<Added>

And should probably initialize the string to null first just in case...
string strUserData = "";


This 23 message thread spans 2 pages: [1]  2  > >  







CodeToad Experts

Can't find the answer?
Our Site experts are answering questions for free in the CodeToad forums
//








Recent Forum Threads
•  Re: Security - Code verify
•  Job @ EarlySail
•  Job @ EarlySail (perl)
•  IPC problem
•  Re: import contacts of msn/yahoo
•  Cookies and Threads C++
•  right justify a background in a table?
•  Help with Loop (C++/MFC)
•  Help with Loop (C++/MFC)


Recent Articles
ASP GetTempName
Decode and Encode UTF-8
ASP GetFile
ASP FolderExists
ASP FileExists
ASP OpenTextFile
ASP FilesystemObject
ASP CreateFolder
ASP CreateTextFile
Javascript Get Selected Text


© Copyright codetoad.com 2001-2007