I'm quite a novice when it comes to user interface development in C ++. Until now I have always started in the Command Window my program.
To start a program I've used the following call.
Prg.exe -slicesize 3 -infill 5 -model cube.stl -ascii -eulerangles 0 0 0
This was processed using the following code
for (int i = 1; i <argc;) {
if (0 == strcmp (argv [i], "-slicesize")) {
slice size = atof (argv [i + 1]);
i + = 2;
}
else if (0 == strcmp (argv [i], "-infill")) {
infill = atof (argv [i + 1]);
i + = 2;
}
else if (0 == strcmp (argv [i], "-model")) {
strcpy (model file name, argv [i + 1]);
i + = 2;
}
else if (0 == strcmp (argv [i], "-ascii")) {
isBinaryFormat = false;
i + = 1;
}
else if (0 == strcmp (argv [i], "-eulerangles")) {
eulerAngles.x = atof (argv [i + 1]);
eulerAngles.y = atof (argv [i + 2]);
eulerAngles.z = atof (argv [i + 3]);
i + = 4;
}
else {
++i;
}
}
The given file, a .stl file, was than processed to a triangle mesh.
TriangleMesh mesh;
if (stlToMeshInMemory(modelFileName, &mesh, isBinaryFormat)!=0)
return 1;
Here, the selected file but must be in the same folder as the program. But the finished program must be dynamic.
Now I have to develop a user interface. For that I have created in my project a button that opens a OpenFileDialog. The path to the selected file is displayed here in a text box.
private: System::Void button3_Click(System::Object^ sender, System::EventArgs^ e) {
OpenFileDialog^ openFileDialog1 = gcnew OpenFileDialog;
openFileDialog1->InitialDirectory = "c:\\";
openFileDialog1->Filter = "stl files (*.stl)|*.stl|All files (*.*)|*.*";
openFileDialog1->FilterIndex = 1;
openFileDialog1->RestoreDirectory = true;
if( openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
textBox1->Text = openFileDialog1->FileName;
}
}
With this code I can search for files and let me see the path. But how can I pass the file name to the function stlToMeshInMemory?
Another question would be to what file I need to program my functions. I use Visual Studio 2012 and have in my project currently three files. Until now I have found the following. In myForm.h [Design] I can make the surface. In myForm.h I program, what should happen when a control element is actuated. In MyForm.cpp I so far only
#include "myForm.h"
using namespace System;
using namespace System :: Windows :: Forms;
[STAThread]
void main (array <String ^> ^ arg) {
Application :: EnableVisualStyles ();
Application :: SetCompatibleTextRenderingDefault (false);
Project2 :: MyForm form;
Application :: Run (% form);
}
Do I have to write the entire program that I've developed in MyForm.cpp? The aim is to read a file and when a button "Translate" is operated to output a file.
Related
In my everyday work I use TortoiseGit and I'm trying to write a post-checkout hook. I prefer to work in Windows-environment so the only thing the hook-file does is call a standard windows .bat-file:
#!/bin/sh
echo "The Git post-checkout Linux Shell-file has now started to execute"
cmd.exe "/c post-checkout.bat"
echo "The Git post-checkout Linux Shell-file has now finished executing"
Inside my standard Windows .bat-file, I do the following:
#echo off
echo --------------------------------------------------------------------------
echo post-checkout.bat in repository root has now started to execute
START /b notepad.exe
echo post-checkout.bat in repository root has now finished executing
echo --------------------------------------------------------------------------
cmd /c exit 0
When I choose Switch/Checkout in TortoiseGit, my hook-file is successfully executed and Notepad starts. However, the strange thing is that the TortoiseGit Git Command Progress dialog hangs until I close Notepad. Please note that I can see "The Git post-checkout Linux Shell-file has now finished executing" in the TortoiseGit Git Command Progress dialog before I close Notepad. If I checkout using the C:\Program Files\Git\bin\bash.exe command window, then I get no hanging issue. Does anybody know how to solve this?
Edit: Putting the following directly in the Linux hook file (i.e. forgetting completely about the Window bat-file) produces the exact same result, the TortoiseGit Git Command Progress dialog hangs until I close Notepad:
#!/bin/sh
echo "The Git post-checkout Linux Shell-file has now started to execute"
notepad &
echo "The Git post-checkout Linux Shell-file has now finished executing"
In the source code https://gitlab.com/tortoisegit/tortoisegit/-/blob/master/src/Utils/Hooks.cpp it can be seen that a hook-file is executed in a new process that is created using CreateProcess and then it waits for the process and all its children to finish by calling WaitForSingleObject (see e.g. this explanation How to start a process and make it 'independent'). So the behavior is very much expected. One solution can be found here https://stackoverflow.com/a/1569941/2075678 which refers to this webpage https://svn.haxx.se/users/archive-2008-11/0301.shtml. I rewrote it slightly:
#include "stdafx.h"
#include <windows.h>
int getFirstIndexOfChar(WCHAR* stringToInvestigate, int startIndex, WCHAR charToLookFor);
int getLastIndexOfChar(WCHAR* stringToInvestigate, int startIndex, WCHAR charToLookFor);
int _tmain(int argc, _TCHAR* argv[])
{
WCHAR* pOriginalCmd = ::GetCommandLine();
// Test code (modify paths to RunDetached.exe and MyFile.txt appropriately)
// pOriginalCmd = _T("\"D:\\My Visual Studio Projects\\RunDetached\\debug\\RunDetached.exe\" \"C:\\Windows\\System32\\notepad.exe\" \"D:\\1.txt\"");
int CmdLen = (int)wcslen(pOriginalCmd);
// Determine where certain characters are located (excl means the particular index is not included, e.g.
// if indexExcl is 5 then index 4 is the last included index).
int beginningOf1stArg = getFirstIndexOfChar(pOriginalCmd, 0, L'\"');
int endOf1stArgExcl = getFirstIndexOfChar(pOriginalCmd, beginningOf1stArg + 1, L'\"') + 1;
int beginningOf2ndArg = getFirstIndexOfChar(pOriginalCmd, endOf1stArgExcl + 1, L'\"');
int endOf2ndArgExcl = getFirstIndexOfChar(pOriginalCmd, beginningOf2ndArg + 1, L'\"') + 1;
int beginningOf3rdArg = getFirstIndexOfChar(pOriginalCmd, endOf2ndArgExcl + 1, L'\"');
int endOfLastArgExcl = getLastIndexOfChar (pOriginalCmd, CmdLen - 1, L'\"') + 1;
int beginningOfFileName = getLastIndexOfChar (pOriginalCmd, endOf2ndArgExcl - 2, L'\\') + 1;
int endOfFileNameExcl = endOf2ndArgExcl - 1;
if ((beginningOf1stArg < 0) || (endOf1stArgExcl < 0) || (beginningOf2ndArg < 0) || (endOf2ndArgExcl < 0) ||
(endOfLastArgExcl < 0) || (beginningOfFileName < 0) || (endOfFileNameExcl < 0))
{
return -1;
}
// Determine the application to execute including full path. E.g. for notepad this should be:
// C:\Windows\System32\notepad.exe (without any double-quotes)
int lengthOfApplicationNameAndPathInChars = (endOf2ndArgExcl -1) - (beginningOf2ndArg + 1); // Skip double-quotes
WCHAR* lpApplicationNameAndPath = (WCHAR*)malloc(sizeof(WCHAR) * (lengthOfApplicationNameAndPathInChars + 1));
memcpy(lpApplicationNameAndPath, &pOriginalCmd[beginningOf2ndArg + 1], sizeof(WCHAR) * (lengthOfApplicationNameAndPathInChars));
lpApplicationNameAndPath[lengthOfApplicationNameAndPathInChars] = (WCHAR)0; // Null terminate
// Determine the command argument. Must be in modifyable memory and should start with the
// application name without the path. E.g. for notepad with command argument D:\MyFile.txt:
// "notepad.exe" "D:\MyFile.txt" (with the double-quotes).
WCHAR* modifiedCmd = NULL;
if (0 < beginningOf3rdArg)
{
int lengthOfApplicationNameInChars = endOfFileNameExcl - beginningOfFileName; // Application name without path
int lengthOfRestOfCmdInChars = CmdLen - beginningOf3rdArg;
int neededCmdLengthInChars = 1 + lengthOfApplicationNameInChars + 2 + lengthOfRestOfCmdInChars; // Two double-quotes and one space extra
modifiedCmd = (WCHAR*)malloc(sizeof(WCHAR) * (neededCmdLengthInChars + 1)); // Extra char is null-terminator
modifiedCmd[0] = L'\"'; // Start with double-quoute
memcpy(&modifiedCmd[1], &pOriginalCmd[beginningOfFileName], sizeof(WCHAR) * (lengthOfApplicationNameInChars));
modifiedCmd[1 + (lengthOfApplicationNameInChars)] = L'\"';
modifiedCmd[1 + (lengthOfApplicationNameInChars) + 1] = L' ';
memcpy(&modifiedCmd[1 + (lengthOfApplicationNameInChars) + 2], &pOriginalCmd[beginningOf3rdArg], sizeof(WCHAR) * lengthOfRestOfCmdInChars);
modifiedCmd[neededCmdLengthInChars] = (WCHAR)0;
}
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
ZeroMemory( &pi, sizeof(pi) );
BOOL result = CreateProcess // Start the detached process.
(
lpApplicationNameAndPath, // Module name and full path
modifiedCmd, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set bInheritHandles to FALSE
DETACHED_PROCESS, // Detach process
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi // Pointer to PROCESS_INFORMATION structure (returned)
);
free(lpApplicationNameAndPath);
if (modifiedCmd != NULL)
{
free(modifiedCmd);
}
if (result) return 0;
wchar_t msg[2048];
FormatMessage
(
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
msg, sizeof(msg),
NULL
);
fputws(msg, stderr);
_flushall();
return -1;
}
int getFirstIndexOfChar(WCHAR* stringToInvestigate, int startIndex, WCHAR charToLookFor)
{
int stringLen = (int)wcslen(stringToInvestigate);
if (5000 < stringLen) // Sanity check
{
return -1;
}
for (int i = startIndex; i < stringLen; i++)
{
if (stringToInvestigate[i] == charToLookFor)
{
return i;
}
}
return -1;
}
int getLastIndexOfChar(WCHAR* stringToInvestigate, int startIndex, WCHAR charToLookFor)
{
int stringLen = (int)wcslen(stringToInvestigate);
if (5000 < stringLen) // Sanity check
{
return -1;
}
for (int i = min(stringLen - 1, startIndex); 0 <= i; i--)
{
if (stringToInvestigate[i] == charToLookFor)
{
return i;
}
}
return -1;
}
After I had compiled the above, I modified my .bat-file and now it works great:
#echo off
echo --------------------------------------------------------------------------
echo post-checkout.bat in repository root has now started to execute
RunDetached notepad
echo post-checkout.bat in repository root has now finished executing
echo --------------------------------------------------------------------------
exit 0
I'm sure this has been addressed in the past. My apologies.
I want to understand why I'm getting error LNK2019.
And what direction to take, to get this resolved.
Errors are LNK2019:
unresolved external symbol __imp__ReportError referenced in function _wmain
unresolved external symbol __imp__Options referenced in function _wmain
This occurs when I build solution in Visual Studio 2010 and up.
Contents of header file for the above methods are described like so:
LIBSPEC DWORD Options (int, LPCTSTR *, LPCTSTR, ...);
LIBSPEC DWORD Options (int, LPCTSTR *, LPCTSTR, ...);
Main code:
#include "Everything.h"
BOOL TraverseDirectory(LPTSTR, LPTSTR, DWORD, LPBOOL);
DWORD FileType(LPWIN32_FIND_DATA);
BOOL ProcessItem(LPWIN32_FIND_DATA, DWORD, LPBOOL);
int _tmain(int argc, LPTSTR argv[])
{
BOOL flags[MAX_OPTIONS], ok = TRUE;
TCHAR searchPattern[MAX_PATH + 1], currPath[MAX_PATH_LONG+1], parentPath[MAX_PATH_LONG+1];
LPTSTR pSlash, pSearchPattern;
int i, fileIndex;
DWORD pathLength;
fileIndex = Options(argc, argv, _T("Rl"), &flags[0], &flags[1], NULL);
pathLength = GetCurrentDirectory(MAX_PATH_LONG, currPath);
if (pathLength == 0 || pathLength >= MAX_PATH_LONG) { /* pathLength >= MAX_PATH_LONG (32780) should be impossible */
ReportError(_T("GetCurrentDirectory failed"), 1, TRUE);
}
if (argc < fileIndex + 1)
ok = TraverseDirectory(currPath, _T("*"), MAX_OPTIONS, flags);
else for (i = fileIndex; i < argc; i++) {
if (_tcslen(argv[i]) >= MAX_PATH) {
ReportError(_T("The command line argument is longer than the maximum this program supports"), 2, FALSE);
}
_tcscpy(searchPattern, argv[i]);
_tcscpy(parentPath, argv[i]);
pSlash = _tstrrchr(parentPath, _T('\\'));
if (pSlash != NULL) {
*pSlash = _T('\0');
_tcscat(parentPath, _T("\\"));
SetCurrentDirectory(parentPath);
pSlash = _tstrrchr(searchPattern, _T('\\'));
pSearchPattern = pSlash + 1;
} else {
_tcscpy(parentPath, _T(".\\"));
pSearchPattern = searchPattern;
}
ok = TraverseDirectory(parentPath, pSearchPattern, MAX_OPTIONS, flags) && ok;
SetCurrentDirectory(currPath);
}
return ok ? 0 : 1;
}
static BOOL TraverseDirectory(LPTSTR parentPath, LPTSTR searchPattern, DWORD numFlags, LPBOOL flags)
{
HANDLE searchHandle;
WIN32_FIND_DATA findData;
BOOL recursive = flags[0];
DWORD fType, iPass, lenParentPath;
TCHAR subdirectoryPath[MAX_PATH + 1];
/* Open up the directory search handle and get the
first file name to satisfy the path name.
Make two passes. The first processes the files
and the second processes the directories. */
if ( _tcslen(searchPattern) == 0 ) {
_tcscat(searchPattern, _T("*"));
}
/* Add a backslash, if needed, at the end of the parent path */
if (parentPath[_tcslen(parentPath)-1] != _T('\\') ) { /* Add a \ to the end of the parent path, unless there already is one */
_tcscat (parentPath, _T("\\"));
}
/* Open up the directory search handle and get the
first file name to satisfy the path name. Make two passes.
The first processes the files and the second processes the directories. */
for (iPass = 1; iPass <= 2; iPass++) {
searchHandle = FindFirstFile(searchPattern, &findData);
if (searchHandle == INVALID_HANDLE_VALUE) {
ReportError(_T("Error opening Search Handle."), 0, TRUE);
return FALSE;
}
do {
fType = FileType(&findData);
if (iPass == 1) /* ProcessItem is "print attributes". */
ProcessItem(&findData, MAX_OPTIONS, flags);
lenParentPath = (DWORD)_tcslen(parentPath);
/* Traverse the subdirectory on the second pass. */
if (fType == TYPE_DIR && iPass == 2 && recursive) {
_tprintf(_T("\n%s%s:"), parentPath, findData.cFileName);
SetCurrentDirectory(findData.cFileName);
if (_tcslen(parentPath) + _tcslen(findData.cFileName) >= MAX_PATH_LONG-1) {
ReportError(_T("Path Name is too long"), 10, FALSE);
}
_tcscpy(subdirectoryPath, parentPath);
_tcscat (subdirectoryPath, findData.cFileName); /* The parent path terminates with \ before the _tcscat call */
TraverseDirectory(subdirectoryPath, _T("*"), numFlags, flags);
SetCurrentDirectory(_T("..")); /* Restore the current directory */
}
/* Get the next file or directory name. */
} while (FindNextFile(searchHandle, &findData));
FindClose(searchHandle);
}
return TRUE;
}
static DWORD FileType(LPWIN32_FIND_DATA pFileData)
{
BOOL isDir;
DWORD fType;
fType = TYPE_FILE;
isDir =(pFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
if (isDir)
if (lstrcmp(pFileData->cFileName, _T(".")) == 0
|| lstrcmp(pFileData->cFileName, _T("..")) == 0)
fType = TYPE_DOT;
else fType = TYPE_DIR;
return fType;
}
static BOOL ProcessItem(LPWIN32_FIND_DATA pFileData, DWORD numFlags, LPBOOL flags)
{
const TCHAR fileTypeChar[] = {_T(' '), _T('d')};
DWORD fType = FileType(pFileData);
BOOL longList = flags[1];
SYSTEMTIME lastWrite;
if (fType != TYPE_FILE && fType != TYPE_DIR) return FALSE;
_tprintf(_T("\n"));
if (longList) {
_tprintf(_T("%c"), fileTypeChar[fType - 1]);
_tprintf(_T("%10d"), pFileData->nFileSizeLow);
FileTimeToSystemTime(&(pFileData->ftLastWriteTime), &lastWrite);
_tprintf(_T(" %02d/%02d/%04d %02d:%02d:%02d"),
lastWrite.wMonth, lastWrite.wDay,
lastWrite.wYear, lastWrite.wHour,
lastWrite.wMinute, lastWrite.wSecond);
}
_tprintf(_T(" %s"), pFileData->cFileName);
return TRUE;
}
The error you're getting is from the linker, and it's telling you that it cannot find the definitions of the ReportError and Options functions (both of which are referenced from your main function).
You say that you have included a header file that contains these functions, but that header contains only the declarations of these functions. You know, like their signature. It doesn't have the body (implementation) of the functions. You need the definition for that.
Definitions for functions that you've written are usually located in *.cpp files. If you've written these functions, make sure that the code file that contains their definitions has been added to your project.
For functions that you have not written (i.e. are part of a reusable library of code), you usually provide the linker with a *.lib file that contains what it needs to call the functions. If these functions are from a library, make sure that you've added the *.lib file that came with them to the list of files that the linker will search. To do that in Visual Studio, follow these steps:
Right-click on your project in the Solution Explorer, and open its Properties.
Expand the "Linker" category, and select the "Input" node.
Click in the "Additional Dependencies" field, and press the ... button.
Enter the name of your *.lib file on a new line in the textbox that appears.
Just because you declared a function in a header file, doesn't mean it has a body anywhere.
The link error says the function doesn't have a body.
This is likely because you didn't link to the proper Library (a .lib file).
I have a C function called "amortiss.c" and I want to connect it to CLIPS (Expert System Tool). Infact, I want to pass the variable "result" returned by the function "amortiss.c" to CLIPS so that it compares this "result" to 1 and then displays messages depending on the comparaison
if (result <1) then (do...);
else if (result ==1) then do (...);
According to the Clips user guide I should define an external function called user-defined function. The problem is that this function is a CLIPS function written in C ..so I don't see how it helps me connect my "amortiss.c" to CLIPS.
Is it also possible to connect Clips to Matlab? (communication between .clp file and .m file)?
I appreciate all your suggestions and advice.
You don't need to define an external function. That would be if you wanted CLIPS to call a C function.
Check out section "4.4.4 CreateFact" in this document:
http://clipsrules.sourceforge.net/documentation/v624/apg.htm
It shows how to assert new facts into the CLIPS environment. The previous section 4.4.3 gives an example how to assert a new string into CLIPS. I have not tested the string assert, but I can confirm the 4.4.4 example works with a deftemplate.
For example, create a text file, "foo.clp":
(deftemplate foo
(slot x (type INTEGER) )
(slot y (type INTEGER) )
)
(defrule IsOne
?f<-(foo (x ?xval))
(test (= ?xval 1))
=>
(printout t ?xval " is equal to 1" crlf)
)
(defrule NotOne
?f<-(foo (x ?xval))
(test (!= ?xval 1))
=>
(printout t ?xval " is not equal to 1" crlf)
)
And create a C program "foo.c"
#include <stdio.h>
#include "clips.h"
int addFact(int result)
{
VOID *newFact;
VOID *templatePtr;
DATA_OBJECT theValue;
//==================
// Create the fact.
//==================
templatePtr = FindDeftemplate("foo");
newFact = CreateFact(templatePtr);
if (newFact == NULL) return -1;
//======================================
// Set the value of the x
//======================================
theValue.type = INTEGER;
theValue.value = AddLong(result);
PutFactSlot(newFact,"x",&theValue);
int rval;
if (Assert(newFact) != NULL){
Run(-1);
rval = 0;
}
else{
rval = -2;
}
return rval;
}
int main(int argc, char *argv[]){
if (argc < 2) {
printf("Usage: ");
printf(argv[0]);
printf(" <Clips File>\n");
return 0;
}
else {
InitializeEnvironment();
Reset();
char *waveRules = argv[1];
int wv = Load(waveRules);
if(wv != 1){
printf("Error opening wave rules!\n");
}
int result = 1;
addFact(result);
result = 3;
addFact(result);
}
return 0;
}
Run with:
foo foo.clp
It might be overkill, but I think it gets the job done!
I have a problem with some code using curses after upgrading to a new server and thus also new software like libs, headers and such.
The problem is the use of the ldat struct fields "firstchar", "lastchar" and "text" which in the the newer versions of curses.h is hidden in the curses.priv.h and therefore they are not resolved.
I could really use some pointers as to how I might be able to resolve these issues.
The code below indicates the use of the struct fields, but it just a part of the complete code as it several thousand lines...
If there is need for additional code I can add this.
I might also add that I have not made this program myself, I'm just responsible for making it work with our new server...
int
update_window(changed, dw, sw, win_shared)
bool *changed;
WINDOW *dw; /* Destination window */
window_t *sw; /* Source window */
bool win_shared;
{
int y, x;
int yind, nx, first, last;
chtype *pd, *ps; /* pd = pointer destination, ps = pointer source */
int nscrolls; /* Number of scrolls to make */
if(! sw->changed) {
*changed = FALSE;
return(0);
}
/****************************************
* Determine number of times window is
* scrolled since last update
****************************************/
nscrolls = sw->scrollcount; if(nscrolls >= sw->ny)
nscrolls = 0;
sw->scrollcount = 0L;
dw->_flags = _HASMOVED;
dw->_cury = sw->cury;
dw->_curx = sw->curx;
if(nscrolls > 0) {
/* Don't copy lines that is scolled away */
for(y = nscrolls; y < sw->ny; y++) {
yind = GETYIND(y - nscrolls, sw->toprow, sw->ny);
if(sw->lastch[yind] != _NOCHANGE) {
first = dw->_line[y].firstchar = sw->firstch[yind];
last = dw->_line[y].lastchar = sw->lastch[yind];
ps = &sw->screen[yind][first];
pd = (chtype *)&dw->_line[y].text[first];
nx = last - first + 1;
LOOPDN(x, nx)
d++ = *ps++;
if(! win_shared) {
sw->firstch[yind] = sw->nx;
sw->lastch[yind] = _NOCHANGE;
}
}
}
} else {
LOOPUP(y, sw->ny) {
yind = GETYIND(y, sw->toprow, sw->ny);
if(sw->lastch[yind] != _NOCHANGE) {
first = dw->_line[y].firstchar = sw->firstch[yind];
last = dw->_line[y].lastchar = sw->lastch[yind];
ps = &sw->screen[yind][first];
pd = (chtype *)&dw->_line[y].text[first];
nx = last - first + 1;
LOOPDN(x, nx)
*pd++ = *ps++;
if(! win_shared) {
sw->firstch[yind] = sw->nx;
sw->lastch[yind] = _NOCHANGE;
}
}
}
if(! win_shared)
sw->changed = FALSE;
}
*changed = TRUE;
return(nscrolls);
}
I appreciate all the help I can get!
The members of struct ldat were made private in June 2001. Reading the function and its mention of scrolls hints that it is writing a portion of some window used to imitate scrolling (by writing a set of lines to the real window), and attempting to bypass the ncurses logic which checks for changed lines.
For a function like that, the only solution is to determine what the developer was trying to do, and write a new function which does this — using the library functions provided.
Basically I'm creating an indoor navigation system in J2ME. I've put the location details in a .txt file i.e.
Locations names and their coordinates.
Edges with respective start node and end node as well as the weight (length of the node).
I put both details in the same file so users dont have to download multiple files to get their map working (it could become time consuming and seem complex).
So what i did is to seperate the deferent details by typing out location Names and coordinates first, After that I seperated that section from the next section which is the edges by drawing a line with multiple underscores.
Now the problem I'm having is parsing the different details into seperate arrays by setting up a command (while manually tokenizing the input stream) to check wether the the next token is an underscore.
If it is, (in pseudocode terms), move to the next line in the stream, create a new array and fill it up with the next set of details.
I found a some explanation/code HERE that does something similar but still parses into one array, although it manually tokenizes the input. Any ideas on what to do? Thanks
Text File Explanation
The text has the following format...
<--1stSection-->
/**
* Section one has the following format
* xCoordinate;yCoordinate;LocationName
*/
12;13;New York City
40;12;Washington D.C.
...e.t.c
_________________________ <--(underscore divider)
<--2ndSection-->
/**
* Its actually an adjacency list but indirectly provides "edge" details.
* Its in this form
* StartNode/MainReferencePoint;Endnode1;distance2endNode1;Endnode2;distance2endNode2;...e.t.c
*/
philadelphia;Washington D.C.;7;New York City;2
New York City;Florida;24;Illinois;71
...e.t.c
package filereader;
import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.Vector;
public class FileReader {
String locationSection;
String edgeSection;
Vector locations;
Vector edges;
public FileReader(String fileName) {
// read the contents into the string
InputStream is = getClass().getResourceAsStream(fileName);
StringBuffer sb = new StringBuffer();
int ch;
try {
while ((ch = is.read()) != -1) {
sb.append((char) ch);
}
} catch (IOException e2) {
e2.printStackTrace();
}
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
String text = sb.toString();
// separate locations and edges
String separator = "_________________________";
// read location section, without last end-of-line char
int endLocationSection = text.indexOf(separator) - 1;
locationSection = text.substring(0, endLocationSection);
// read edges section, without end-of-line char after separator
int startEdgeSection = endLocationSection + separator.length() + 3;
edgeSection = text.substring(startEdgeSection, text.length());
// parse locations and edges
locations = getLocationsVector(locationSection);
edges = getEdgesVector(edgeSection);
}
// parse locations section
public Vector getLocationsVector(String section) {
Vector result = new Vector();
int startLine = 0;
int endLine = section.indexOf('\n');
while (endLine != -1) {
String line = section.substring(startLine, endLine);
result.addElement(parseLocationsLine(line, ';'));
startLine = endLine + 1;
if (endLine == section.length() - 1)
break;
endLine = section.indexOf('\n', startLine);
// if no new line found, read to the end of string
endLine = (-1 == endLine) ? section.length() - 1 : endLine;
}
return result;
}
// parse edges section
public Vector getEdgesVector(String section) {
Vector result = new Vector();
int startLine = 0;
int endLine = section.indexOf('\n');
while (endLine != -1) {
String line = section.substring(startLine, endLine - 1);
result.addElement(parseEdgesLine(line, ';'));
startLine = endLine + 1;
if (endLine == section.length() + 1)
break;
endLine = section.indexOf('\n', startLine);
// if no new line found, read to the end of string
endLine = (-1 == endLine) ? section.length() + 1 : endLine;
}
return result;
}
// parse locations line
public Hashtable parseLocationsLine(String value, char splitBy) {
Hashtable result = new Hashtable();
int xCEnd = value.indexOf(splitBy);
int yCEnd = value.indexOf(splitBy, xCEnd + 1);
result.put("x", value.substring(0, xCEnd));
result.put("y", value.substring(xCEnd + 1, yCEnd));
result.put("location", value.substring(yCEnd + 1,
value.length() - 1));
return result;
}
// parse edges line
public Hashtable parseEdgesLine(String value, char splitBy) {
Hashtable result = new Hashtable();
int snEnd = value.indexOf(splitBy);
result.put("startnode", value.substring(0, snEnd));
int n = 1;
int start = snEnd + 1;
int enEnd = value.indexOf(splitBy, snEnd + 1);
int dstEnd = value.indexOf(splitBy, enEnd + 1);
while (enEnd != -1 && dstEnd != -1) {
result.put("endnode" + String.valueOf(n),
value.substring(start, enEnd));
result.put("distance" + String.valueOf(n), value.substring(
enEnd + 1, dstEnd));
start = dstEnd + 1;
enEnd = value.indexOf(splitBy, start);
if (dstEnd == value.length())
break;
dstEnd = value.indexOf(splitBy, enEnd + 1);
// if last endnode-distance pair, read to the end of line
dstEnd = (-1 == dstEnd) ? value.length() : dstEnd;
n++;
}
return result;
}
// getters for locations and edges
public Vector getLocations() {
return locations;
}
public Vector getEdges() {
return edges;
}
}
and somewhere in application screen:
fr = new FileReader("/map.txt");
Vector vct1 = fr.getLocations();
for (int i = 0; i < vct1.size(); i++) {
Hashtable location = (Hashtable) vct1.elementAt(i);
Enumeration en = location.keys();
String fv = "";
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
String value = (String)location.get(key);
fv = fv + value + "-";
}
this.add(new LabelField(fv));
}
Vector vct2 = fr.getEdges();
for (int i = 0; i < vct2.size(); i++) {
Hashtable location = (Hashtable) vct2.elementAt(i);
Enumeration en = location.keys();
String fv = "";
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
String value = (String)location.get(key);
fv = fv + value + "-";
}
this.add(new LabelField(fv));
}
it will be easy to get values from hashtable by keys:
(String)location.get("x")
(String)location.get("y")
(String)location.get("location")
(String)edge.get("startnode")
(String)edge.get("endnode1")
(String)edge.get("distance1")
(String)edge.get("endnode2")
(String)edge.get("distance2")
...