Created
February 29, 2020 01:40
-
-
Save chronologicaldot/6a62e74e3810dfb80064041ac93891c6 to your computer and use it in GitHub Desktop.
Program that converts Metasequoia (.mqo) files to Wavefront Object (.obj) and vice versa
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Cedar Cocoon | |
(c) 2011, Nicolaus Anderson | |
This is free and opensource software. | |
This software is provided AS IS without any guarantee that it will function. | |
The program is supposed to convert .mqo files to .obj files and vice versa. | |
Some functionality is not built in, thus certain aspects of models will not carry over | |
to the output file during conversion. | |
*/ | |
// Using standard input/output library | |
#include <iostream> | |
// Using strings library | |
#include <string> | |
// Using file input and output libraries | |
#include <ostream> | |
using namespace std; | |
// Using file reader | |
#include "Freader.cpp" | |
// Using Linus Listor (linked list) | |
#include "LinusListorCp.cpp" | |
using namespace Linus; | |
// universal variables | |
// file to be converted | |
string input_file; | |
// file extension | |
string input_file_extension; | |
// new file extension | |
string output_file_extension; | |
// file reader | |
Freader reader; | |
// file output object | |
ofstream output; | |
// function prototypes | |
void converter_switch(int); | |
bool convert_mqo_to_obj(); | |
// class for material information | |
class ELEM_material { | |
public: | |
// name of the material | |
string name; | |
// plain color info | |
float color[3]; // 0 = transparency/alpha, 1 = red, 2 = green, 3 = blue | |
// ambient color | |
float amb[3]; // 0 = red, 1 = green, 2 = blue | |
// diffuse color | |
float dif; | |
// specular color | |
float spec; | |
}; | |
// class for vertices information | |
class ELEM_vertex { | |
public: | |
float x; | |
float y; | |
float z; | |
int group; // the group that this vertex belongs to | |
}; | |
// class for face information | |
class ELEM_face { | |
public: | |
int v[4]; | |
// v[4] = zero if only three vertices | |
bool v4th; | |
void swap(int elem, int elem2) { | |
int orig = 0; | |
orig = v[elem]; | |
v[elem] = v[elem2]; | |
v[elem2] = orig; | |
} | |
// material information | |
int mat; // which material (note: .mqo begins listing with 0; .obj begins with 1) | |
}; | |
// Main function | |
void main() | |
{ | |
// user response | |
string response; | |
// Console is displayed | |
cout << "\n\nWelcome to Cedar Cocoon Converter v1.0\nby Nic Anderson"; | |
do { | |
// Request that the user input information about the file they want to convert | |
cout << "\n\nPlease enter the name of the file to convert\n:"; | |
cin >> input_file; | |
cout << "\n\nPlease pick the type of conversion:" | |
<< "\n1) Metasequoia (.mqo) to Wavefront object (.obj)" | |
<< "\n:"; | |
cin >> response; | |
converter_switch( atoi(response.c_str()) ); | |
// ask if repetition desired | |
cout << "\n\nWould you like to convert another file?(y/n)\n:"; | |
cin >> response; | |
// continue while the user wants to | |
} while ( response == "y" ); | |
} | |
// Conversion switch: delegates which function will do the converting | |
void converter_switch(int conv) | |
{ | |
switch (conv) | |
{ | |
case 1: // mqo to obj | |
input_file_extension = "mqo"; | |
output_file_extension = "obj"; | |
if ( convert_mqo_to_obj() ) | |
cout << "\n\nJob completed successfully.\n"; | |
else | |
cout << "\n\nJob failed."; | |
default: | |
cout << "\n\nNo other conversions available."; | |
break; | |
} | |
} | |
//==================================================== | |
// Conversion function for metasequoia to object files | |
/* | |
LOGIC: | |
Read from the mqo file using the reader function. | |
Skip the header, the scene and the scene sections. | |
*/ | |
bool convert_mqo_to_obj() | |
{ | |
// object for holding the information found in file | |
string package; | |
// string new output name | |
string output_name = input_file; | |
// set the file reader to the beginning of the new file | |
reader.read_position = 0; | |
reader.FileName = input_file.append("." + input_file_extension); | |
// create a new output file with the output extension appended | |
output.open( (output_name.append(".obj")).c_str() ); | |
/* now the tricky part... | |
Metasequoia file format: | |
1) Header - basic info about the file | |
2) Scene - how Metasequoia is to display the file upon loadup (unimportant for .obj) | |
3) Material - color information that is shared amongst the faces | |
4) Object - contains the vertices and face information. | |
NOTE: There may be multiple objects. Furthermore, there is mirroring. | |
To handle mirroring, reserve x-number of vertices for every one vertex, where "x" is | |
the number of extra vertices per new vertex in the model (min 0, max 7 (for all 8 | |
regions)). | |
*/ | |
// skip the header and the scene info in the .mqo file | |
/* | |
1) Search for material definition sections | |
2) Scan for and through the "objects" | |
*/ | |
/* | |
When scanning through the material definition sections: | |
Parts to look for: | |
> { | |
Preceded by a number indicating the the total number of materials and | |
followed by the definitions of the materials themselves. | |
> "name" | |
Material's name, which isn't important, but will be used for the name | |
of the texture in the .obj file anyways. | |
> col | |
This is followed by parenthesis containing the exact color information | |
in order of: alpha, red, green, blue. Values range from 0 to 1, and an | |
alpha setting of 1 gives no transparency (the material is a solid color). | |
> | |
*/ | |
// list for containing all of the materials and their information | |
LListor<ELEM_material> * materials = new LListor<ELEM_material>(); | |
// material to add to the list | |
ELEM_material mtr; | |
/* | |
When scanning through the objects: | |
Parts to look for: | |
> { | |
This is important considering that mirroring information can change with | |
multiple objects. | |
> vertex | |
Each object will have its own set of vertices. However, .obj files only | |
allow for all of the vertices to be placed in the beginning of them. | |
> face | |
As with vertices, each object will have its own set of faces. However, .obj | |
files only allow for all of the faces to be in the middle of the file | |
following the section giving the vertices. | |
*/ | |
// mirroring type | |
//int mirror = 1; // 1 = separate, 2 = joined (not supported yet) | |
// axis of reflection | |
int mirror_axis = 0; | |
/* | |
>> 0 for none | |
>> 1 for x alone | |
>> 2 for y alone | |
>> 3 for y and x | |
>> 4 for z alone | |
>> 5 for z and x | |
>> 6 for z and y | |
>> 7 for x, y, and z axis | |
*/ | |
// multiplicand for the vertex index | |
int multiplicand = 1; | |
// list for containing all of the vertices and their information | |
LListor<ELEM_vertex> * vertices = new LListor<ELEM_vertex>(); | |
// list for containing all of the faces and their information | |
LListor<ELEM_face> * faces = new LListor<ELEM_face>(); | |
// vertex to add to the list | |
ELEM_vertex vtx; | |
// face to add to the list | |
ELEM_face fce; | |
// special characters | |
#define all_specials 5 | |
char specials[all_specials]; | |
specials[0] = '\n'; | |
specials[1] = '('; | |
specials[2] = ')'; | |
specials[3] = '{'; | |
specials[4] = '}'; | |
// identify all of the objects | |
do { | |
package = reader.readFromFile_sys_ns(all_specials, specials); | |
/* | |
NOTE: A .mtl file must be created to save the material of the model. | |
// found a material definition section | |
if ( package == "Material" ) { | |
// search for the open curly bracket | |
// Note, in doing so, we skip the indicator of the total number of materials. | |
do { | |
package = reader.readFromFile_sys_ns(all_specials, specials); | |
} while ( package != "{" ); | |
cout << "\nNow scanning materials:" | |
do { // while there are materials | |
// store the first one in the package in case this is the last one | |
package = reader.readFromFile_sys_nse(all_specials, specials); | |
if ( package == "}" ) break; | |
// the first item should be the name | |
package = reader.readFromFile_ns(false); | |
mtr.name = package; | |
// scan for the material information until at the end of the line | |
do { | |
package = reader.readFromFile_ns(true); | |
// if color info | |
if ( package == "col" ) { | |
// first search should turn up an open parenthesis | |
package = reader.readFromFile_sys_ns(all_specials, specials); | |
// the next four searches should give the argb values | |
mtr.color[0] = reader.readFromFile_ns(false); | |
mtr.color[1] = reader.readFromFile_ns(false); | |
mtr.color[2] = reader.readFromFile_ns(false); | |
mtr.color[3] = reader.readFromFile_ns(false); | |
} | |
} while ( package != "\n" ); | |
// creation of a new slot in the list | |
materials = materials->addNewLink(mtr, false); | |
// NOTE: the last link in the chain will be duplicate of the last | |
cout << "."; | |
} while ( package != "}" ); | |
} | |
*/ | |
// found an object | |
if ( package == "Object" ) { | |
// indicate that this is the next group being examined | |
curr_grp += 1; | |
// search for the open curly bracket | |
do { | |
package = reader.readFromFile_sys_ns(all_specials, specials); | |
} while ( package != "{" ); | |
// search for the keyword "vertex" or "mirror_axis" | |
do { | |
package = reader.readFromFile_sys_ns(all_specials, specials); | |
// there is a reflection axis | |
if ( package == "mirror_axis" ) { | |
// identify the axis | |
package = reader.readFromFile_sys_ns(all_specials, specials); | |
// convert this to a numeric value | |
mirror_axis = atoi( package.c_str() ); | |
// set the multiplicand | |
switch(mirror_axis) | |
{ | |
case 1: | |
case 2: multiplicand = 2; break; | |
case 3: multiplicand = 4; break; | |
case 4: multiplicand = 2; break; | |
case 5: | |
case 6: multiplicand = 4; break; | |
case 7: multiplicand = 8; break; | |
default: multiplicand = 1; break; | |
} | |
} | |
} while ( package != "vertex" ); | |
/* Following "vertex" is a number giving the total number of | |
vertices, which in turn is followed by an open curly bracket. */ | |
do { | |
package = reader.readFromFile_sys_ns(all_specials, specials); | |
} while ( package != "{" ); | |
/* Now that the keyword "vertex" has been found: | |
Examine each vertex, each of which consists of three numbers on a | |
single line. */ | |
// update | |
cout << "\nNow scanning vertices:"; | |
do { // while there are vertices | |
// store the first one in the package in case this is the last one | |
package = reader.readFromFile_sys_nse(all_specials, specials); | |
if ( package == "}" ) break; | |
// new vertex | |
vtx.x = atof( package.c_str() ); | |
vtx.y = atof( reader.readFromFile_sys_nse(all_specials, specials).c_str() ); | |
vtx.z = atof( reader.readFromFile_sys_nse(all_specials, specials).c_str() ); | |
// copy the new vertex to the list | |
vertices->setThisItem(vtx); | |
// check for mirroring | |
switch ( mirror_axis ) | |
{ | |
/* NOTE: mirroring requires that the new vertex have a | |
negative/opposite value of the original. | |
*/ | |
case 1: // x axis | |
vtx.x = -vtx.x; | |
vertices = vertices->addNewLink(vtx, false); | |
break; | |
case 2: // y axis | |
vtx.y = -vtx.y; | |
vertices = vertices->addNewLink(vtx, false); | |
break; | |
case 3: // x and y axis | |
// x axis | |
vtx.x = -vtx.x; // now negative | |
vertices = vertices->addNewLink(vtx, false); | |
// y axis | |
vtx.x = -vtx.x; // now positive | |
vtx.y = -vtx.y; // now negative | |
vertices = vertices->addNewLink(vtx, false); | |
// x and y axis | |
vtx.x = -vtx.x; // now negative | |
vertices = vertices->addNewLink(vtx, false); | |
break; | |
case 4: // z axis | |
vtx.z = -vtx.z; | |
vertices = vertices->addNewLink(vtx, false); | |
break; | |
case 5: // x and z axis | |
// x axis | |
vtx.x = -vtx.x; | |
vertices = vertices->addNewLink(vtx, false); | |
// z axis | |
vtx.x = -vtx.x; | |
vtx.z = -vtx.z; | |
vertices = vertices->addNewLink(vtx, false); | |
// x and z axis | |
vtx.x = -vtx.x; | |
vertices = vertices->addNewLink(vtx, false); | |
break; | |
case 6: // y and z axis | |
// y axis | |
vtx.y = -vtx.y; | |
vertices = vertices->addNewLink(vtx, false); | |
// z axis | |
vtx.y = -vtx.y; | |
vtx.z = -vtx.z; | |
vertices = vertices->addNewLink(vtx, false); | |
// y and z axis | |
vtx.y = -vtx.y; | |
vertices = vertices->addNewLink(vtx, false); | |
break; | |
case 7: // x, y, and z axis | |
// x axis | |
vtx.x = -vtx.x; // now negative | |
vertices = vertices->addNewLink(vtx, false); | |
// y axis | |
vtx.x = -vtx.x; // now positive | |
vtx.y = -vtx.y; // now negative | |
vertices = vertices->addNewLink(vtx, false); | |
// z axis | |
vtx.y = -vtx.y; // now positive | |
vtx.z = -vtx.z; // now negative | |
vertices = vertices->addNewLink(vtx, false); | |
// x and y axis | |
vtx.x = -vtx.x; // now negative | |
vtx.y = -vtx.y; // now negative | |
vtx.z = -vtx.z; // now positive | |
vertices = vertices->addNewLink(vtx, false); | |
// x and z axis | |
vtx.y = -vtx.y; // now positive | |
vtx.z = -vtx.z; // now negative | |
vertices = vertices->addNewLink(vtx, false); | |
// y and z axis | |
vtx.x = -vtx.x; // now positive | |
vtx.y = -vtx.y; // now negative | |
vertices = vertices->addNewLink(vtx, false); | |
// x, y, and z axis | |
vtx.x = -vtx.x; // now negative | |
vertices = vertices->addNewLink(vtx, false); | |
break; | |
default: break; // no mirroring | |
} | |
// creation of a new slot in the list | |
vertices = vertices->addNewLink(vtx, false); | |
// NOTE: the last link in the chain will be duplicate of the last | |
cout << "."; | |
} while ( package != "}" ); | |
// the next thing should be "face" | |
do { | |
package = reader.readFromFile_sys_ns(all_specials, specials); | |
} while ( package != "face" && package != "}" ); | |
// if at the end of the object | |
if ( package == "}" ) break; | |
/* "face" will be followed by a number indicating the total number of faces | |
in the model and an open curly bracket */ | |
do { | |
package = reader.readFromFile_sys_ns(all_specials, specials); | |
} while ( package != "{" ); | |
// update | |
cout << "\nNow scanning faces:"; | |
// obtain all of the faces | |
do { | |
// number indicating the number of vertices in the face | |
package = reader.readFromFile_sys_nse(all_specials, specials); | |
// in case there are no more faces | |
if ( package == "}" ) break; | |
switch ( atoi( package.c_str() ) ) | |
{ | |
case 3: // ensure that the last face vertex index is set to zero | |
fce.v[3] = 0; // no fourth vertex | |
fce.v4th = false; | |
break; | |
default: // assume four | |
fce.v4th = true; | |
break; | |
} | |
/* Recall that for mirroring, vertices were added. Therefore, the | |
vertex index is shifted up so many places to account for the new | |
points from the mirroring. The shift, based on the number of vertices | |
added by the switch (see above) will be 1, 3, or 7. | |
This number + 1 will be the multiplicand of the index to give the | |
new index. | |
*/ | |
// each face is on a new line | |
do { | |
package = reader.readFromFile_sys_ns(all_specials, specials); | |
if ( package == "V" ) // vertices | |
{ | |
// first search should turn up an open parenthesis | |
package = reader.readFromFile_sys_ns(all_specials, specials); | |
// next three searches should be of the vertices composing the face | |
// new vertex index = old vertex index * multiplicand | |
fce.v[0] = atoi( reader.readFromFile_sys_ns(all_specials, specials).c_str() ) | |
* multiplicand; | |
fce.v[1] = atoi( reader.readFromFile_sys_ns(all_specials, specials).c_str() ) | |
* multiplicand; | |
fce.v[2] = atoi( reader.readFromFile_sys_ns(all_specials, specials).c_str() ) | |
* multiplicand; | |
// if there is a fourth vertex | |
if ( fce.v4th ) | |
fce.v[3] = atoi( reader.readFromFile_sys_ns(all_specials, specials).c_str() ) | |
* multiplicand; | |
else | |
fce.v[3] = 0; | |
// add this face to the list | |
faces->setThisItem(fce); | |
// now consider the mirror axis (ignoring mirror type for now) | |
switch( mirror_axis ) | |
{ | |
case 1: // x axis | |
case 2: // y axis | |
fce.v[0] = fce.v[0] + 1; | |
fce.v[1] = fce.v[1] + 1; | |
fce.v[2] = fce.v[2] + 1; | |
fce.swap(0,1); // swap 0 and 1 | |
if ( fce.v4th ) // if there is a fourth vertex | |
{ | |
fce.v[3] = fce.v[3] + 1; | |
fce.swap(2,3); | |
} | |
faces = faces->addNewLink(fce,false); // add the new face | |
break; | |
case 3: // x and y | |
fce.swap(0,1); // swap 0 and 1 | |
if ( fce.v4th ) fce.swap(2,3); | |
for ( int i = 1; i <= 3; i++ ) | |
{ | |
fce.v[0] = fce.v[0] + 1; | |
fce.v[1] = fce.v[1] + 1; | |
fce.v[2] = fce.v[2] + 1; | |
if ( fce.v4th ) // if there is a fourth vertex | |
fce.v[3] = fce.v[3] + 1; | |
if ( i == 3 ) | |
{ | |
// switch back | |
fce.swap(0,1); // swap 0 and 1 | |
if ( fce.v4th ) fce.swap(2,3); | |
} | |
faces = faces->addNewLink(fce,false); // add the new face | |
} | |
break; | |
case 4: // z | |
fce.v[0] = fce.v[0] + 1; | |
fce.v[1] = fce.v[1] + 1; | |
fce.v[2] = fce.v[2] + 1; | |
fce.swap(0,1); // swap 0 and 1 | |
if ( fce.v4th ) // if there is a fourth vertex | |
{ | |
fce.v[3] = fce.v[3] + 1; | |
fce.swap(2,3); | |
} | |
faces = faces->addNewLink(fce,false); // add the new face | |
break; | |
case 5: // x and z | |
case 6: // y and z | |
fce.swap(0,1); // swap 0 and 1 | |
if ( fce.v4th ) fce.swap(2,3); | |
for ( int i = 1; i <= 3; i++ ) | |
{ | |
fce.v[0] = fce.v[0] + 1; | |
fce.v[1] = fce.v[1] + 1; | |
fce.v[2] = fce.v[2] + 1; | |
if ( fce.v4th ) // if there is a fourth vertex | |
fce.v[3] = fce.v[3] + 1; | |
if ( i == 3 ) | |
{ | |
// switch back | |
fce.swap(0,1); // swap 0 and 1 | |
if ( fce.v4th ) fce.swap(2,3); | |
} | |
faces = faces->addNewLink(fce,false); // add the new face | |
} | |
break; | |
case 7: // x, y, and z | |
fce.swap(0,1); // swap 0 and 1 | |
if ( fce.v4th ) fce.swap(2,3); | |
for ( int i = 1; i <= 7; i++ ) | |
{ | |
fce.v[0] = fce.v[0] + 1; | |
fce.v[1] = fce.v[1] + 1; | |
fce.v[2] = fce.v[2] + 1; | |
if ( fce.v4th ) // if there is a fourth vertex | |
fce.v[3] = fce.v[3] + 1; | |
switch(i) | |
{ | |
case 4: | |
case 7: | |
// switch back | |
fce.swap(0,1); // swap 0 and 1 | |
if ( fce.v4th ) fce.swap(2,3); | |
break; | |
default: break; | |
} | |
faces = faces->addNewLink(fce,false); // add the new face | |
} | |
break; | |
default: break; | |
} | |
} | |
// if ( package == "M" ) // material - not implemented yet | |
// if ( package == "UV" ) // lighting - not implemented yet | |
} while ( package != "\n" ); | |
// add the new face to the list | |
faces = faces->addNewLink(fce,false); | |
cout << "."; | |
} while ( package != "}" ); | |
// Now search fo the last curly bracket defining the "Object" | |
do { | |
package = reader.readFromFile_sys_ns(all_specials, specials); | |
} while ( package != "}" ); | |
} | |
} while ( package != "Eof" ); | |
/* TO .OBJ ******************************* */ | |
/* Now that the file information has been obtained, store it in an ANSI | |
encoded text file in the .obj format. | |
*/ | |
// generic "group" | |
output << "g only\n"; | |
// identify the total number of vertices as well as return the pointer to the first | |
int v_size = 0; | |
// assume starting at the last link | |
while ( vertices->hasWhat() == 1 || vertices->hasWhat() == 3 ) { | |
vertices = vertices->getPriorLink(); | |
v_size++; | |
} | |
// identify the total number of faces as well as return the pointer to the first | |
int f_size = 0; | |
// assume starting at the last link | |
while ( faces->hasWhat() == 1 || faces->hasWhat() == 3 ) { | |
faces = faces->getPriorLink(); | |
f_size++; | |
} | |
// add the vertex information to the file | |
for ( int vx = 0; vx < v_size; vx++ ) | |
{ | |
output << "\nv " | |
<< vertices->getThisItemCopy().x << " " | |
<< vertices->getThisItemCopy().y << " " | |
<< vertices->getThisItemCopy().z << " " | |
; | |
vertices = vertices->getPostLink(); | |
} | |
// add the face information to the file | |
for ( int fa = 0; fa < f_size; fa++ ) | |
{ | |
output << "\nf " | |
<< (faces->getThisItemCopy().v[0] + 1) << " " | |
<< (faces->getThisItemCopy().v[1] + 1) << " " | |
<< (faces->getThisItemCopy().v[2] + 1) << " " | |
; | |
if ( faces->getThisItemCopy().v4th ) | |
output << (faces->getThisItemCopy().v[3] + 1) << " "; | |
faces = faces->getPostLink(); | |
} | |
// completed the conversion | |
return true; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <fstream> | |
#include <string> | |
using namespace::std; | |
/* Class functions for obtaining characters and strings | |
from standard text files. | |
(C) Nic Anderson | |
July 7, 2011 | |
*/ | |
class Freader { | |
public: | |
int read_position; | |
string FileName; | |
/* Functions used to call readFromFile functions repeatedly when spaces are not | |
desired. */ | |
string readFromFile_ns(bool delim) | |
{ | |
string ret; | |
do { | |
ret = readFromFile( delim ); | |
} while ( ret == " " ); | |
return ret; | |
} | |
string readFromFile_sys_ns(int _MaxSystemChars, char system_chars[]) | |
{ | |
string ret; | |
do { | |
ret = readFromFile_sys( _MaxSystemChars, system_chars ); | |
} while ( ret == " " ); | |
return ret; | |
} | |
string readFromFile_sys_nse(int _MaxSystemChars, char system_chars[]) | |
{ | |
string ret; | |
do { | |
ret = readFromFile_sys( _MaxSystemChars, system_chars ); | |
} while ( ret == " " || ret == "\n" ); | |
return ret; | |
} | |
/* Function used to obtain objects (tokens) from files. | |
\param delim - whether the newline character is singly considered a token. */ | |
string readFromFile(bool delim) | |
{ | |
/* prepare and open a file for reading */ | |
ifstream theFile; | |
theFile.open( FileName.c_str() ); | |
/* Set the get() position to the latest location. */ | |
theFile.seekg( read_position, ios::cur ); | |
/* read individual characters from the file */ | |
// prep: create necessary variables | |
char character = ' '; /* This stores the character to be placed in a | |
string and returned to the function that called this | |
function */ | |
bool set = false; /* Indicates whether or not the loop that collects | |
characters from file (and puts them in a string) should | |
be repeated. */ | |
bool set_fail = false; /* Indicates whether or not to reset the set variable so | |
that the character-collecting loop can continue. */ | |
int count = 0; /* Used in for-loop to compare system characters with | |
each new character extracted from file. */ | |
// initialize a string to return to the function that called this one | |
string strng; | |
strng.clear(); | |
//********************************** | |
// check to see if it is possible to get a character | |
character = theFile.get(); | |
// do only if it is possible to extract characters | |
if ( theFile.good() ) | |
{ | |
/* Revert to the first character. This prevents the | |
interior do-while loop from messing up. */ | |
theFile.seekg(-1, ios::cur); | |
// get characters from file | |
do | |
{ | |
// get a character from the file | |
character = theFile.get(); | |
/* Get rid of any tabs. Turn them into spaces. */ | |
if (character == ' ') | |
{ character = ' '; } | |
/* Terminate search for letters if the character obtained from | |
file is a space. */ | |
if (character == ' ') | |
{ | |
set = true; // indicate the loop should end | |
} | |
/* Terminate search for letters if the character obtained from | |
file is a newline. */ | |
if ( character == '\n' && delim == true ) | |
{ | |
set = true; // indicate the loop should end | |
} | |
// Add the character if it is going to be the only one in the word. | |
if ( set == false || strng.length() == 0 ) | |
{ | |
// Add the character to the word | |
strng.push_back( character ); | |
/* Consider adding another character to the word ONLY if it | |
is a number, since this might be a floating point decimal | |
number. */ | |
if ( character == '.' | |
&& ( theFile.peek() == '0' || theFile.peek() == '1' | |
|| theFile.peek() == '2' || theFile.peek() == '3' | |
|| theFile.peek() == '4' || theFile.peek() == '5' | |
|| theFile.peek() == '6' || theFile.peek() == '7' | |
|| theFile.peek() == '8' || theFile.peek() == '9' ) ) | |
{ | |
set = false; | |
} | |
} else { | |
// Apparently, set was true, so a system character was found | |
/* Only let a period be added to the word as long as there | |
is no other period in the word already. */ | |
if ( character == '.' | |
&& ( strng[0] == '0' || strng[0] == '1' | |
|| strng[0] == '2' || strng[0] == '3' | |
|| strng[0] == '4' || strng[0] == '5' | |
|| strng[0] == '6' || strng[0] == '7' | |
|| strng[0] == '8' || strng[0] == '9' | |
) ) | |
/* NOTE: Only the first character in the word needs | |
to be looked at, since the period will be added if it | |
is going to be the first character in the word anyways. | |
A number at the beginning of the word automatically | |
indicates a floating decimal number. | |
Minus signs are to be handled under the '-' data manipulator. */ | |
{ | |
// The system character is a period. | |
// Check for a period already in the word | |
set_fail = false; // assume there is no period in the word | |
// start looking for a period in the word | |
for (unsigned int w = 0; w < strng.length(); w++) | |
{ | |
if (strng[w] == '.') | |
{ set_fail = true; } | |
} | |
if ( set_fail == true ) | |
{ | |
/* If there is a period in the word already, allow | |
the second period to be picked up next time. */ | |
theFile.seekg(-1, ios::cur); | |
} else { | |
// Add the period to the end of the word | |
strng.push_back( character ); | |
/* only consider adding another character to the string | |
if the character is a decimal place or a number */ | |
if ( theFile.peek() == '0' || theFile.peek() == '1' | |
|| theFile.peek() == '2' || theFile.peek() == '3' | |
|| theFile.peek() == '4' || theFile.peek() == '5' | |
|| theFile.peek() == '6' || theFile.peek() == '7' | |
|| theFile.peek() == '8' || theFile.peek() == '9' ) | |
{ | |
set = false; | |
} | |
} | |
} else { | |
/* The string length was not zero, or the character was | |
not a period. */ | |
/* The system character was not added to the end of a word, | |
so allow it to be extracted next time. */ | |
theFile.seekg(-1, ios::cur); | |
} | |
} | |
/* Don't collect more characters if the file is at its end. | |
Simply return what has been collected already. */ | |
if ( !theFile.good() && strng.length() > 0 ) | |
{ | |
/* Set the reading position to the point before the end. */ | |
theFile.seekg( -1, ios::cur ); | |
/* Store the reading position. */ | |
read_position = theFile.tellg(); | |
/* Return what has been acquired. */ | |
return strng; | |
} | |
} while ( set == false && theFile.good() ); | |
/* Store the reading position. */ | |
read_position = theFile.tellg(); | |
//************************************ | |
// WHAT TO DO IF AT THE END OF MAIN | |
if ( !theFile.good() ) | |
{ | |
/* assign "end_main" to the return string to indicate the | |
end of the file has been reached */ | |
strng = "end_main"; | |
// close the file | |
theFile.close(); | |
// end the readFromFile() use here | |
return strng; | |
} // endif WHAT TO DO IF AT THE END OF MAIN | |
else // normal shut down | |
{ | |
theFile.close(); | |
} | |
} //********************************* | |
// endif - file fails to open | |
else { | |
/* assign "end_main" to the return string to indicate the | |
end of the file has been reached */ | |
strng = "end_main"; | |
// close the file | |
theFile.close(); | |
} //********************************** | |
// return the string | |
return strng; | |
} | |
//==================================================== | |
/* Function used to obtain objects (tokens) from files | |
considering special characters. | |
\param delim - whether the newline character is singly considered a token. */ | |
string readFromFile_sys(int _MaxSystemChars, char system_chars[]) | |
{ | |
/* prepare and open a file for reading */ | |
ifstream theFile; | |
theFile.open( FileName.c_str() ); | |
/* Set the get() position to the latest location. */ | |
theFile.seekg( read_position, ios::cur ); | |
/* read individual characters from the file */ | |
// prep: create necessary variables | |
char character = ' '; /* This stores the character to be placed in a | |
string and returned to the function that called this | |
function */ | |
bool set = false; /* Indicates whether or not the loop that collects | |
characters from file (and puts them in a string) should | |
be repeated. */ | |
bool set_fail = false; /* Indicates whether or not to reset the set variable so | |
that the character-collecting loop can continue. */ | |
int count = 0; /* Used in for-loop to compare system characters with | |
each new character extracted from file. */ | |
// initialize a string to return to the function that called this one | |
string strng; | |
strng.clear(); | |
//********************************** | |
// check to see if it is possible to get a character | |
character = theFile.get(); | |
// do only if it is possible to extract characters | |
if ( theFile.good() ) | |
{ | |
/* Revert to the first character. This prevents the | |
interior do-while loop from messing up. */ | |
theFile.seekg(-1, ios::cur); | |
// get characters from file | |
do | |
{ | |
// get a character from the file | |
character = theFile.get(); | |
/* Get rid of any tabs. Turn them into spaces. */ | |
if (character == ' ') | |
{ character = ' '; } | |
/* check to make sure that the character is not a system command | |
character */ | |
for (count = 0; count < _MaxSystemChars; count++) | |
{ | |
/* If a character is a system character, plan to get rid of it. */ | |
if ( character == system_chars[count] ) | |
{ set = true; } | |
} | |
/* Terminate search for letters if the character obtained from | |
file is a space. */ | |
if (character == ' ') | |
{ | |
set = true; // indicate the loop should end | |
} | |
// Add the character if it is going to be the only one in the word. | |
if ( set == false || strng.length() == 0 ) | |
{ | |
// Add the character to the word | |
strng.push_back( character ); | |
/* Consider adding another character to the word ONLY if it | |
is a number, since this might be a floating point decimal | |
number. */ | |
if ( character == '.' | |
&& ( theFile.peek() == '0' || theFile.peek() == '1' | |
|| theFile.peek() == '2' || theFile.peek() == '3' | |
|| theFile.peek() == '4' || theFile.peek() == '5' | |
|| theFile.peek() == '6' || theFile.peek() == '7' | |
|| theFile.peek() == '8' || theFile.peek() == '9' ) ) | |
{ | |
set = false; | |
} | |
} else { | |
// Apparently, set was true, so a system character was found | |
/* Only let a period be added to the word as long as there | |
is no other period in the word already. */ | |
if ( character == '.' | |
&& ( strng[0] == '0' || strng[0] == '1' | |
|| strng[0] == '2' || strng[0] == '3' | |
|| strng[0] == '4' || strng[0] == '5' | |
|| strng[0] == '6' || strng[0] == '7' | |
|| strng[0] == '8' || strng[0] == '9' | |
) ) | |
/* NOTE: Only the first character in the word needs | |
to be looked at, since the period will be added if it | |
is going to be the first character in the word anyways. | |
A number at the beginning of the word automatically | |
indicates a floating decimal number. | |
Minus signs are to be handled under the '-' data manipulator. */ | |
{ | |
// The system character is a period. | |
// Check for a period already in the word | |
set_fail = false; // assume there is no period in the word | |
// start looking for a period in the word | |
for (unsigned int w = 0; w < strng.length(); w++) | |
{ | |
if (strng[w] == '.') | |
{ set_fail = true; } | |
} | |
if ( set_fail == true ) | |
{ | |
/* If there is a period in the word already, allow | |
the second period to be picked up next time. */ | |
theFile.seekg(-1, ios::cur); | |
} else { | |
// Add the period to the end of the word | |
strng.push_back( character ); | |
/* only consider adding another character to the string | |
if the character is a decimal place or a number */ | |
if ( theFile.peek() == '0' || theFile.peek() == '1' | |
|| theFile.peek() == '2' || theFile.peek() == '3' | |
|| theFile.peek() == '4' || theFile.peek() == '5' | |
|| theFile.peek() == '6' || theFile.peek() == '7' | |
|| theFile.peek() == '8' || theFile.peek() == '9' ) | |
{ | |
set = false; | |
} | |
} | |
} else { | |
/* The string length was not zero, or the character was | |
not a period. */ | |
/* The system character was not added to the end of a word, | |
so allow it to be extracted next time. */ | |
theFile.seekg(-1, ios::cur); | |
} | |
} | |
/* Don't collect more characters if the file is at its end. | |
Simply return what has been collected already. */ | |
if ( !theFile.good() && strng.length() > 0 ) | |
{ | |
/* Set the reading position to the point before the end. */ | |
theFile.seekg( -1, ios::cur ); | |
/* Store the reading position. */ | |
read_position = theFile.tellg(); | |
/* Return what has been acquired. */ | |
return strng; | |
} | |
} while ( set == false && theFile.good() ); | |
/* Store the reading position. */ | |
read_position = theFile.tellg(); | |
//************************************ | |
// WHAT TO DO IF AT THE END OF MAIN | |
if ( !theFile.good() ) | |
{ | |
/* assign "end_main" to the return string to indicate the | |
end of the file has been reached */ | |
strng = "end_main"; | |
// close the file | |
theFile.close(); | |
// end the readFromFile() use here | |
return strng; | |
} // endif WHAT TO DO IF AT THE END OF MAIN | |
else // normal shut down | |
{ | |
theFile.close(); | |
} | |
} //********************************* | |
// endif - file fails to open | |
else { | |
/* assign "end_main" to the return string to indicate the | |
end of the file has been reached */ | |
strng = "end_main"; | |
// close the file | |
theFile.close(); | |
} //********************************** | |
// return the string | |
return strng; | |
} | |
//============================================================== | |
/* Function for getting a select number of characters from file */ | |
string readFileChars( int obtain ) | |
{ | |
/* prepare and open a file for reading */ | |
ifstream theFile; | |
theFile.open( FileName.c_str() ); | |
/* Set the get() position to the latest location. */ | |
theFile.seekg( read_position, ios::cur ); | |
/* read individual characters from the file */ | |
// prep: create necessary variables | |
char character = ' '; /* This stores the character to be placed in a | |
string and returned to the function that called this | |
function */ | |
int count = 0; /* Used in while loop to compare the number of characters | |
stored in the string with the number of characters | |
desired in the string. */ | |
// initialize a string to return to the function that called this one | |
string strng; | |
//********************************** | |
// check to see if it is possible to get a character | |
character = theFile.get(); | |
// do only if it is possible to extract characters | |
if ( theFile.good() ) | |
{ | |
/* Revert to the first character. This prevents the | |
interior do-while loop from messing up. */ | |
theFile.seekg(-1, ios::cur); | |
// get characters from file | |
do | |
{ | |
// get a character from the file | |
character = theFile.get(); | |
// store the character in the string | |
strng.push_back( character ); | |
// indicate another character has been put in the string | |
count++; | |
} while ( theFile.good() && count < obtain ); | |
/* Store the reading position. */ | |
read_position = theFile.tellg(); | |
//************************************ | |
// WHAT TO DO IF AT THE END OF MAIN | |
if ( !theFile.good() ) | |
{ | |
/* assign "end_main" to the return string to indicate the | |
end of the file has been reached */ | |
strng = "end_main"; | |
// close the file | |
theFile.close(); | |
// end the readFromFile() use here | |
return strng; | |
} // endif WHAT TO DO IF AT THE END OF MAIN | |
else // normal shut down | |
{ | |
theFile.close(); | |
} | |
} //********************************* | |
// endif - file fails to open | |
else { | |
/* assign "end_main" to the return string to indicate the | |
end of the file has been reached */ | |
strng = "end_main"; | |
// close the file | |
theFile.close(); | |
} //********************************** | |
// return the string | |
return strng; | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Name: Linus Listor for C++ | |
(Linus Listor C Plus / Linus Listor Cp ) | |
(C) Nic Anderson | |
Date: June 15, 2011 | |
See LinusListorCp.h for copyright details. | |
Desc: This is a simple linked list for C++ programs. | |
*/ | |
#ifndef _LLISTOR_ | |
#define _LLISTOR_ | |
// include the header | |
#include "LinusListorCp.h" | |
namespace Linus | |
{ | |
template<class Unk> | |
LListor<Unk>::LListor() | |
{ | |
// indicate this link has neither prior nor post links | |
possession_state = s_none; | |
} | |
// for the item being stored | |
template<class Unk> | |
Unk* LListor<Unk>::getThisItemAddress() | |
{ | |
return &ThisItem; | |
} | |
template<class Unk> | |
Unk LListor<Unk>::getThisItemCopy() | |
{ | |
return ThisItem; | |
} | |
template<class Unk> | |
void LListor<Unk>::setThisItem(Unk newItem) | |
{ | |
ThisItem = newItem; | |
} | |
// for the prior and post links | |
template<class Unk> | |
LListor<Unk>* LListor<Unk>::getPriorLink() | |
{ | |
if ( possession_state == s_prior || possession_state == s_both ) | |
return PriorLink; | |
else return 0; | |
} | |
template<class Unk> | |
void LListor<Unk>::setPriorLink( LListor<Unk>* newPrior ) | |
{ | |
// set the new link (NOTE: Does not delete the old one in case it is needed) | |
PriorLink = newPrior; | |
// adjust the possession state if necessary | |
switch ( possession_state ) | |
{ | |
case s_none: possession_state = s_prior; break; | |
case s_prior: break; | |
case s_post: possession_state = s_both; break; | |
case s_both: break; | |
} | |
} | |
template<class Unk> | |
LListor<Unk>* LListor<Unk>::getPostLink() | |
{ | |
if ( possession_state == s_post || possession_state == s_both ) | |
return PostLink; | |
else return 0; | |
} | |
template<class Unk> | |
void LListor<Unk>::setPostLink( LListor<Unk>* newPost ) | |
{ | |
// set the new link (NOTE: Does not delete the old one in case it is needed) | |
PostLink = newPost; | |
// adjust the possession state if necessary | |
switch ( possession_state ) | |
{ | |
case s_none: possession_state = s_post; break; | |
case s_prior: possession_state = s_both; break; | |
case s_post: break; | |
case s_both: break; | |
} | |
} | |
// possession state | |
template<class Unk> | |
si32 LListor<Unk>::hasWhat() | |
{ | |
switch ( possession_state ) | |
{ | |
case s_none: return 0; | |
case s_prior: return 1; | |
case s_post: return 2; | |
case s_both: return 3; | |
} | |
} | |
// for adding on new links onto the chain | |
template<class Unk> | |
LListor<Unk>* LListor<Unk>::addNewLink( Unk item , bool head ) | |
{ | |
// save the location of the new link, based on whether it is the prior or post | |
if (head) // prior | |
{ | |
// determine if this link has a prior link already | |
switch ( possession_state ) | |
{ | |
case s_none: | |
// create a new link - use "new" to ensure it isn't deleted from the stack | |
PriorLink = new LListor<Unk>; | |
// assign it the new item | |
PriorLink->setThisItem(item); | |
// indicate the prior link now has a post link | |
PriorLink->setPostLink(this); | |
// indicate that this now has a prior link | |
possession_state = s_prior; | |
break; | |
case s_prior: | |
// considering this has a prior, send the item to that link to be added | |
return PriorLink->addNewLink( item, true ); | |
//break; - unnecessary after a "return" statement | |
case s_post: | |
// create a new link - use "new" to ensure it isn't deleted from the stack | |
PriorLink = new LListor<Unk>; | |
// assign it the new item | |
PriorLink->setThisItem(item); | |
// indicate the prior link now has a post link | |
PriorLink->setPostLink(this); | |
// indicate this link now has both links | |
possession_state = s_both; | |
break; | |
case s_both: | |
// considering this has a prior, send the item to that link to be added | |
return PriorLink->addNewLink( item, true ); | |
//break; - unnecessary after a return statement | |
} | |
// return the pointer to the link of the new object | |
return PriorLink; | |
} else { | |
// indicate that this link now has a new post link | |
switch ( possession_state ) | |
{ | |
case s_none: | |
// create a new link - use "new" to ensure it isn't deleted from the stack | |
PostLink = new LListor<Unk>; | |
// assign it the new item | |
PostLink->setThisItem(item); | |
// indicate the post link now has a prior link | |
PostLink->setPriorLink(this); | |
// indicate this link now has a post link | |
possession_state = s_post; | |
break; | |
case s_prior: | |
// create a new link - use "new" to ensure it isn't deleted from the stack | |
PostLink = new LListor<Unk>; | |
// assign it the new item | |
PostLink->setThisItem(item); | |
// indicate the post link now has a prior link | |
PostLink->setPriorLink(this); | |
// indicate this link now has both links | |
possession_state = s_both; | |
break; | |
case s_post: | |
// considering this has a post, send the item to that link to be added | |
return PostLink->addNewLink( item, false ); | |
//break; - unnecessary after a return statement | |
case s_both: | |
// considering this has a post, send the item to that link to be added | |
return PostLink->addNewLink( item, false ); | |
//break; - unnecessary after a return statement | |
} | |
// return the pointer to the link of the new object | |
return PostLink; | |
} | |
} | |
// for removing the current link from its current chain without deleting it | |
template<class Unk> | |
void LListor<Unk>::extractCurrLink() const | |
{ | |
// check for whether this link has a prior and a post link | |
if ( possession_state == s_both ) | |
{ | |
PriorLink->setPostLink( PostLink ); | |
PostLink->setPriorLink( PriorLink ); | |
} | |
switch( possession_state ) | |
{ | |
case s_prior: | |
switch ( PriorLink->possession_state ) | |
{ | |
case s_post: PriorLink->possession_state = s_none; break; | |
case s_both: PriorLink->possession_state = s_prior; break; | |
default: break; | |
} | |
break; | |
case s_post: // flag that the prior link has been dropped | |
switch ( PostLink->possession_state ) | |
{ | |
case s_prior: PostLink->possession_state = s_none; break; | |
case s_both: PostLink->possession_state = s_post; break; | |
default: break; | |
} | |
break; | |
case s_both: // bridge the chain | |
PriorLink->setPostLink( PostLink ); | |
PostLink->setPriorLink( PriorLink ); | |
break; | |
default: break; | |
} | |
} | |
// for properly deleting the current link in the chain | |
template<class Unk> | |
void LListor<Unk>::delCurrLink() const | |
{ | |
// check for whether this link has a prior and a post link | |
extractCurrLink(); | |
// finally, delete this link | |
delete this; | |
} | |
// for scanning the chain | |
template<class Unk> | |
LListor<Unk>* LListor<Unk>::getFirstLink() | |
{ | |
// if this link itself has a prior link, call it | |
if ( possession_state == s_prior || possession_state == s_both ) | |
return PriorLink->getFirstLink(); | |
else | |
return this; // otherwise, this (the current) link is the one to return | |
} | |
template<class Unk> | |
LListor<Unk>* LListor<Unk>::getLastLink() | |
{ | |
// if this link itself has a prior link, call it | |
if ( possession_state == s_post || possession_state == s_both ) | |
return PostLink->getLastLink(); | |
else | |
return this; // otherwise, this (the current) link is the one to return | |
} | |
} | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This is the header file for LinusListorCp.cpp | |
(C) Nic Anderson | |
Date: June 15, 2011 | |
This software is provided 'as-is', without any express or implied | |
warranty. In no event will the authors be held liable for any damages | |
arising from the use of this software. | |
Permission is granted to anyone to use this software for any purpose, | |
including commercial applications, and to alter it and redistribute it | |
freely, subject to the following restrictions: | |
1. The origin of this software must not be misrepresented; you must not | |
claim that you wrote the original software. If you use this software | |
in a product, an acknowledgment in the product documentation would be | |
appreciated but is not required. | |
2. Altered source versions must be plainly marked as such, and must not be | |
misrepresented as being the original software. | |
3. This notice may not be removed or altered from any source distribution. | |
*/ | |
// don't double define this | |
// if "_Linus_INCLUDED" is not defined... | |
#ifndef _Linus_INCLUDED_ | |
// ... define it (and define the namespace as well) | |
#define _Linus_INCLUDED_ | |
// simple definitions for usage with this list | |
#ifdef _MSC_VER | |
typedef __int32 si32; | |
#else | |
typedef signed int si32; | |
#endif | |
namespace Linus | |
{ | |
// The main class in Linus - the actual linked list | |
template<class Unk> | |
class LListor | |
{ | |
private: | |
// pointers to the prior link and post link (links before and after this one) | |
LListor<Unk>* PriorLink; | |
LListor<Unk>* PostLink; | |
/* indicates the posession state: | |
if this link has a link before it, after it, or both */ | |
enum { | |
s_none = 0, | |
s_prior, | |
s_post, | |
s_both | |
} possession_state; | |
public: | |
// object being pointed to | |
Unk ThisItem; | |
//! Default constructor | |
/** Sets the possession state to zero, indicating this link | |
has neither a link that preceeds it nor one that follows. */ | |
LListor(); | |
// Dealing with the user's item being stored in the list | |
//! Return item address | |
/** This returns the address of the item/object | |
being pointed to by this class's pointer. */ | |
virtual Unk* getThisItemAddress(); | |
//! Return item copy | |
/** This returns a copy of the item/object | |
being pointed to by this class's pointer. */ | |
virtual Unk getThisItemCopy(); | |
//! Set/replace item | |
/** This sets a new item for this pointer or | |
replaces the current one. */ | |
virtual void setThisItem(Unk newItem); | |
// Dealing with the chain | |
//! Return prior link | |
/** This returns a pointer to the link that | |
comes before this one in the chain. */ | |
virtual LListor<Unk>* getPriorLink(); | |
//! Set prior link | |
/** This sets a pointer to the link that is | |
now to precede this one. */ | |
virtual void setPriorLink( LListor<Unk>* newPrior ); | |
//! Return post link | |
/** This returns a pointer to the link that | |
follows this one in the chain. */ | |
virtual LListor<Unk>* getPostLink(); | |
//! Set post link | |
/** This sets a pointer to the link that is | |
now to follow this one. */ | |
virtual void setPostLink( LListor<Unk>* newPost ); | |
//! Get possession state | |
/** This returns one of four values, indicating what links | |
it has: | |
0 if it has neither a preceeding/prior link nor a following/post, | |
1 if it has a prior link, | |
2 if it has a post link, | |
3 if it has both a prior and a post link. */ | |
virtual si32 hasWhat(); | |
//! Add new link | |
/** Generate an entirely new link, assign it | |
the given object, and append it to this link. | |
\param item = new object being added | |
\param head = if this link is the new prior */ | |
virtual LListor<Unk>* addNewLink( Unk item , bool head ); | |
//! Extract the current link | |
/** Takes a link out of the chain it currently belongs to | |
without deleting it. The gap in the old chain is linked | |
by the linking of the former post and prior links of the | |
extracted link. */ | |
virtual void extractCurrLink() const; | |
//! Delete the current link | |
/** Removes the current link in the chain by assigning | |
the post link and previous link to each other, returning | |
one of the two (post takes precedence over prior) if | |
available. The removed link is then deleted. */ | |
virtual void delCurrLink() const; | |
//! Delete the next link | |
/** Removes the next link in the chain, if it exists, | |
and by calling delCurrLink() on its post link. */ | |
void delPostLink() const | |
{ | |
if ( possession_state == s_post || possession_state == s_both ) | |
{ | |
this->getPostLink()->delCurrLink(); | |
} | |
} | |
//! Delete the previous link | |
/** Removes the previous link in the chain, if it exists, | |
and by calling delCurrLink() on its post link. */ | |
void delPriorLink() const | |
{ | |
if ( possession_state == s_prior || possession_state == s_both ) | |
{ | |
this->getPriorLink()->delCurrLink(); | |
} | |
} | |
//! Get the first link in the chain | |
/** This returns the first link whose possession state | |
indicates it does not have a prior link. */ | |
virtual LListor<Unk>* getFirstLink(); | |
//! Get the last link in the chain | |
/** This returns the last link whose possession state | |
indicates it does not have a post link. */ | |
virtual LListor<Unk>* getLastLink(); | |
//! Compare items | |
/** Apply greater-than comparison operation to the | |
items pointed to by the links. */ | |
void operator> ( LListor<Unk>* ll_out ) | |
{ | |
return ( ThisItem > ll_out->getThisItemCopy() ); | |
} | |
//! Compare items | |
/** Apply less-than comparison operation to the | |
items pointed to by the links. */ | |
void operator< ( LListor<Unk>* ll_out ) | |
{ | |
return ( ThisItem < ll_out->getThisItemCopy() ); | |
} | |
//! Compare items | |
/** Apply greater-than-or-equal-to comparison operation | |
to the items pointed to by the links. */ | |
void operator>= ( LListor<Unk>* ll_out ) | |
{ | |
return ( ThisItem >= ll_out->getThisItemCopy() ); | |
} | |
//! Compare items | |
/** Apply less-than-or-equal-to comparison operation | |
to the items pointed to by the links. */ | |
void operator<= ( LListor<Unk>* ll_out ) | |
{ | |
return ( ThisItem <= ll_out->getThisItemCopy() ); | |
} | |
//! Compare items | |
/** Apply not-equal-to comparison operation to the | |
items pointed to by the links. */ | |
void operator!= ( LListor<Unk>* ll_out ) | |
{ | |
return ( ThisItem != ll_out->getThisItemCopy() ); | |
} | |
//! Compare items | |
/** Apply the equal-to comparison operations to the | |
items pointed to by the links. */ | |
void operator== ( LListor<Unk>* ll_out ) | |
{ | |
return ( ThisItem == ll_out->getThisItemCopy() ); | |
} | |
}; | |
// type definitions (essentially just shortcuts) | |
//typedef LListor<int> LLii; | |
//typedef LListor<float> LLif; | |
} | |
// end the definition | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment