Directory navigation in OPEN clause - fortran

How can I read from a parent directory using the OPEN clause? Let's say
OPEN (11,file='../inf/input.dat',form='formatted',status='old')
, which doesn't work. I get:
forrtl: severe (29): file not found, unit 11, file /home/cg/compile/comp/../inf/input.dat
I would like to read from the parent directory just before inf. Is that possible?

Unfortunately there is no unique way to do this, since paths are OS dependent. In order to this in a robust way you might need to define a function that look for the OS while preprocessing (cf. compilation flags e.g. here).
For *nix systems (Unix, including OSX, and Linux) the option you provided should suffice
../
in the path goes to the previous directory.
However in windows there is no way that I know to go in the above directory (I don't have a Windows system with me at the moment).
However you can workaround this limitation with the GetModuleFileName API function. (note that this will not work in the systems above)
CHARACTER*(*) pathname ! full name
INTEGER L ! length
L= GetModuleFileName(NULL,pathname,LEN(pathname))
Fullname will now contain the full path where you run your program, so you can do all sort of string operation you want.
If you want to go above one level
Idx = index(trim(pathname), '/', .True.)
Finds the index of the last '/' character in the pathname (you might need to look for the one before the last).
outfile_path=pathname(:idx)+'/inf/input.dat'
will be now the path you want.

Related

Windows up one directory from current path

I have been searching for hours but cant find a solution to this as yet. Apologies it is probably really simple.
My program is using CreateDirectory to create a new directory and then set the path to it to receive a number of data files:
if (CreateDirectory(dateTime.c_str(), NULL) || ERROR_ALREADY_EXISTS == GetLastError())
{
SetCurrentDirectory(dateTime.c_str());
}
Once all the data files have been generated I would like to move back up one directory without specifying the absolute path. Something equivalent to cd.. or ../ Does anyone know the best way to do this?
One possible approach is to get the current directory (GetCurrentDirectory) before changing to a new one and once complete, then change back the desired directory; akin to a push/pop.
In the sample I've left out error checking and buffer size requirements for simplicity.
TCHAR resetDir[1024] = {};
GetCurrentDirectory(1024, resetDir);
//... Do some work, change directories etc...
// Reset the directory
SetCurrentDirectory(resetDir);
Side note: the current directory when the process is launched is not necessarily the same as the directory the process image is in (the exe path).
Relative changes can be done with a simple
SetCurrentDirectory(_T(".."));
Although basing the relative from the current directory would also work (and may be preferable);
SetCurrentDirectory((currentDir + _T("\\..")).c_str());
Internally, cd command ends using SetCurrentDirectory. So to get something equivalent to cd.. or cd ../ you can simply use:
cr = ::SetCurrentDirectory("..");
cr should be non zero if it succeded and 0 if it failed. In the latter case use GetLastError to get further information.

Diagnosing QDir::rmdir failure

I’m using the following code to delete an empty folder on Linux:
bool removeFolder (const QString& path)
{
QDir dir(path);
assert(dir.exists());
return dir.rmdir(".");
}
For some reason it sometimes returns false (for specific folders, but those folders don’t seem to be wrong in any way). If I subsequently use ::rmdir from <unistd.h> to remove the same folder, it succeeds.
How can I tell why QDir::rmdir is failing?
This never happened on Windows so far, QDir::rmdir just works.
Confirming: works on windown, fails on linux.
Reading the "rmdir" doc in <unistd>, here https://pubs.opengroup.org/onlinepubs/007904875/functions/rmdir.html, it says there that "If the path argument refers to a path whose final component is either dot or dot-dot, rmdir() shall fail." So what's probably happening is that QDir::rmdir() is calling the unistd rmdir() function in linux, and this one fails with ".".
I tried to just use the full absolute path ( QDir::rmdir(absolutePath) ) and it worked; however, i see basically no point in using QDir::rmdir() over unistd's rmdir(), so i''ll stick w/ the unistd rmdir() from now on.
note: QDir::removeRecursively() is a different story: it seems to work okay, and it's way more convenient than going through opendir() and then successive readdir()'s (or the nftw(...FTW_DEPTH...) thingie).
I had the same problem but on Windows, I could not delete an empty directory with QDir().rmdir(path);. This happened on some older hard drive so may be the ancient file system was to blame. But I found a hack:
QFile(path).setPermissions(QFile::WriteOther); // this works even for dirs
bool success = QDir().rmdir(path);
Of course, you should revert the permissions back to original values if the deletion was unsuccessful anyway, but that's a different story.
Try to use this one:
dir.rmdir(dir.absolutePath())

Get proper case working directory?

To better familiarize myself with C++, I'm redoing an old college OS assignment: program your own shell. I'm using all sorts of Windows.h that I've never known existed. So far I've made good progress but I've noticed something about my cd implementation and my working directory I get back from getcwd.
My cd command does some error checking but ultimately it comes down to chdir(path). Say I'm at C:\ and there exists a folder FOLDER. If I use chdir("folder") then later when I call getcwd(dir, FILENAME_MAX) then I'll get the string C:\folder instead of the case correct string C:\FOLDER. How can I retrieve the working directory with every folder having the proper case?
Note: When I first start my shell and run my pwd command (that solely prints dir from my getcwd call), I get a path that is properly cased. As soon as I start changing the working directory then the casing always matches my strings instead of the actual folder casing.
I think the Windows command prompt just uses GetLongPathName, which returns the path with appropriate casing (however, it doesn't change the drive letter's casing).
If you want an uppercase drive letter, the GetShortPathName function returns the short path with the driver letter capitalized. You can then pass this short path to GetLongPathName, which will turn it into a properly cased long path, but this isn't what cmd does.
You can also use SHGetFileInfo, but it's not the easiest approach.
You can use the GetFullPathName API function to return the proper (case correct) path of the current directory, as in the following example:
TCHAR tchPath[MAX_PATH];
GetFullPathName(TEXT("."), MAX_PATH, tchPath, NULL);

how to JUDGE other program's result via cpp?

I've got a series of cpp source file and I want to write another program to JUDGE if they can run correctly (give input and compare their output with standart output) . so how to:
call/spawn another program, and give a file to be its standard input
limit the time and memory of the child process (maybe setrlimit thing? is there any examples?)
donot let the process to read/write any file
use a file to be its standard output
compare the output with the standard output.
I think the 2nd and 3rd are the core part of this prob. Is there any way to do this?
ps. system is Linux
To do this right, you probably want to spawn the child program with fork, not system.
This allows you to do a few things. First of all, you can set up some pipes to the parent process so the parent can supply the input to the child, and capture the output from the child to compare to the expected result.
Second, it will let you call seteuid (or one of its close relatives like setreuid) to set the child process to run under a (very) limited user account, to prevent it from writing to files. When fork returns in the parent, you'll want to call setrlimit to limit the child's CPU usage.
Just to be clear: rather than directing the child's output to a file, then comparing that to the expected output, I'd capture the child's output directly via a pipe to the parent. From there the parent can write the data to a file if desired, but can also compare the output directly to what's expected, without going through a file.
std::string command = "/bin/local/app < my_input.txt > my_output_file.txt 2> my_error_file.txt";
int rv = std::system( command.c_str() );
1) The system function from the STL allows you to execute a program (basically as if invoked from a shell). Note that this approach is inherenly insecure, so only use it in a trusted environment.
2) You will need to use threads to be able to achieve this. There are a number of thread libraries available for C++, but I cannot give you recommendation.
[After edit in OP's post]
3) This one is harder. You either have to write a wrapper that monitors read/write access to files or do some Linux/Unix privilege magic to prevent it from accessing files.
4) You can redirect the output of a program (that it thinks goes to the standard output) by adding > outFile.txt after the way you would normally invoke the program (see 1)) -- e.g. otherapp > out.txt
5) You could run diff on the saved file (from 3)) to the "golden standard"/expected output captured in another file. Or use some other method that better fits your need (for example you don't care about certain formatting as long as the "content" is there). -- This part is really dependent on your needs. diff does a basic comparing job well.

Executing a command from C++, What is expected in argv[0]?

I am using execv() to run commands from /bin/ such as 'ls', 'pwd', 'echo' from my c++ program, and I am wondering what value I should provide in argv[0];
const char * path = getPath();
char ** argv = getArgs();
execv(path,argv);
argv[0] is supposed to be the program name. It's passed to the program's main function. Some programs differentiate their behavior depending on what string argv[0] is. For example the GNU bash shell will disable some of its features if called using sh instead of bash. Best give it the same value that you pass to path.
In linux, argv[0] is the process name displayed by the top utility (which it probably gets from reading entries in /proc/)
argv[0] should be the full path of the command that you want to run.
I know that this is not the answer you're looking for but is there a specific reason why you're doing this? The reason I ask is that most if not all of the actions people normally run with either system() or execv() are available in libraries on either Windows or Unix and are safer, faster and less likely to suffer from circumstantial errors. By that I mean, for example, when the PATH changes and suddenly your code stops working.
If you're passing in a string, either in whole or in part, and running it then you also leave yourself open to a user gaining access to the system by entering a command that could be damaging. E.g. imagine you've implemented a file search using find /home -name and your user types in:
"%" -exec rm {} \;
Ouch!