As part of a little project, I'm writing a shell in Ada. As such, when I was investigating the system calls, I learned that there are three ways to do it.
The POSIX system calls, which are probably the least reliable.
Passing the arguments along to C's system(), which I didn't really want to do, since this was about writing the emulator in Ada and not C.
Using GNAT's runtime libraries.
I chose to go for the last option, considering this to be the most "Ada-like" of the choices. I found a code snippet on RosettaCode here. I copied and pasted it and compiled it after changing the "cmd.exe" to "ls" and removing the second argument definition. However, nothing happens when I run the executable. The shell just goes right back to the prompt. I have tested this on two different computers, one running Fedora 21, the other Debian Jessie. Here's what I've done to test it:
Seen if lacking an arguments string caused it
Checked if any of the file descriptors in GNAT's libraries are mis-named
Redirected both stderr and stdin to stdout just to see if GNAT was dumping them to the wrong FD anyway.
Looked thoroughly through the System.OS_lib library file, and there seems to be no reason.
Googled it, but GNAT's own page on the GCC website is very poorly documented.
For now I'm using the C.Interface system in the preparation of my shell, but I'm dissatisfied with this. I'm new to Ada and have only been tinkering with it for a month or so now, so if there's some kind of Ada wisdom here that would help I'm not in on it.
UPDATE: I have tried running it with absolute path, both to /usr/bin and /bin locations, and it doesn't work. Interestingly, the result code returned by the operating system is 1, but I don't know what that means. A quick search suggests that it's for "all general errors", and another site suggests that it's for "incorrect functions".
I had to tweak the RosettaCode example a little to run /bin/ls on Debian Linux, but it does run as expected...
with Ada.Text_IO; use Ada.Text_IO;
with Gnat.OS_Lib; use Gnat.OS_Lib;
procedure Execute_Synchronously is
Result : Integer;
Arguments : Argument_List :=
( 1=> new String'("-al")
);
begin
Spawn
( Program_Name => "/bin/ls",
Args => Arguments,
Output_File_Descriptor => Standout,
Return_Code => Result
);
for Index in Arguments'Range loop
Free (Arguments (Index));
end loop;
end Execute_Synchronously;
Changes :
my Gnat (FSF Gnat 4.92 from Debian Jessie) warned about System.OS_Lib, recommending Gnat.OS_Lib instead. (Which simply renames System.OS_Lib .... why???
System.OS_Lib comments:
-- Note: this package is in the System hierarchy so that it can be directly
-- be used by other predefined packages. User access to this package is via
-- a renaming of this package in GNAT.OS_Lib (file g-os_lib.ads).
Program name including path.
Arguments. The first time I ran it, it displayed the details of "ls" itself, because it was given its own name as the first argument, so I deleted that to see the current directory instead.
Notes :
the best information ot the available subprograms and their arguments is usually in the package specs themselves in the "adainclude" folder : this is /usr/lib/gcc/x86_64-linux-gnu/4.9/adainclude on my Debian installation, locate system.ads will find yours. The specific files are: s-os_lib.ads for System.OS_Lib which exports Spawn and Standout, and a-textio.ads for Ada.Text_IO.
Standout is not the preferred way of accessing Standard Output : it's a file descriptor (integer), the preferred way would be the Standard_Output function from Ada.Text_IO which returns a File. However there doesn't seem to be an overload for Spawn which takes a File (nor would I expect one in this low level library) so the lower level file descriptor is used here.
Absent a shell, you'll need to search the PATH yourself or specify a full path for the desired executable:
Spawn (
Program_Name => "/bin/ls",
…
);
I have tried running it with absolute path…neither /usr/bin nor /bin locations work.
Use which to determine the full path to the executable:
$ which ls
/bin/ls
Related
I'm trying to run a Perl script called WyD using Cygwin on Windows. Cygwin is installed at C:\cygwin64, and WyD is installed at C:\wyd\wyd.pl. Both are in the Windows PATH environment variable as C:\cygwin64 and C:\wyd respectively.
When running WyD with bash/Mintty using:
wyd.pl -b -e -t -s 3 -o "OUTPUTTEDWORDLIST" "TARGETFOLDER"
...I get the following error:
Can't locate object method "init" via package "wlgmod::odt" (perhaps
you forgot to load "wlgmod::odt"?) at /cygdrive/c/WYD/wyd.pl line 284.
Sometimes wlgmod::odt is replaced with wlgmod::doc or any other document type, but running the script always generates that same basic error. A previous answer to this question recommended installing several dependencies, which turned out to be a mere copy-paste of an answer for Ubuntu systems, and didn't solve the error, so I've decided to start at the beginning and re-ask the question with more details. I also have all Perl packages in the Cygwin installer installed.
After everything I've tried and done to get this script working, I can personally think of two possible causes for the error. Think of these as a guide more than anything else.
The error above references line 284 in the wyd.pl script, so it's possible that something in that script is hardcoded so that it doesn't work with Cygwin/Windows, or just generally has a compatibility bug. I don't understand Perl, so I can't confirm this.
I notice that the installation of WyD at C:\wyd contains a folder called wlgmod, and that folder contains all the files that the above error seems to be looking for; doc.pm, html.pm, jpeg.pm, etc. If those files exist in that directory but bash is unable to find them, maybe it's due to the fact WyD needs to be run from within Cygwin itself. I've only recently thought about this possibility, and my knowledge of both Cygwin and WyD is too sparse to definitively know how both work. Is it even possible to run WyD from within the Cygwin folder? It's not a package so can't be installed as one, and therefore I'm not sure how that would work.
Here are the relevant sections of the script:
# Module hash containing module name and supported file extensions
# Multiple extensions are seperated using ';'
my %wlgmods = (
'wlgmod::strings', '', # only used with command-line switch
'wlgmod::plain' , '.txt', # used for all MIME text/plain as well
'wlgmod::html' , '.html;.htm;.php;.php3;.php4',
'wlgmod::doc' , '.doc',
'wlgmod::pdf' , '.pdf',
'wlgmod::mp3' , '.mp3',
'wlgmod::ppt' , '.ppt',
'wlgmod::jpeg' , '.jpeg;.jpg;.JPG;.JPEG',
'wlgmod::odt' , '.odt;.ods;.odp'
);
...
# Initialize possible modules
foreach(keys %wlgmods) {
eval("use $_;");
my $ret = $_->init(); # line 284
# If module failed, add errortext and remove from hash
if($ret) {
$retvals .= "$_: $ret\n";
delete $wlgmods{$_};
$ret = "";
}
}
Does python have a simple function for checking if a directory is an actual directory or if it's just an alias to another directory? I'm trying to list all files/folders in a directory but because of these alias folders, I'm getting a lost of stuff that looks like this:
/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bundle/Home/bundle/Home/bundle/Home/bundle/Home/bundle/Home/bundle/Home/bundle/Home/bundle/Home/bundle/Home/bundle/Home/bundle
I know I can write a function that will compare paths and quit if it seems like I'm going in circles, but is there a simple function that does exactly that that I'm not aware of?
E.g.
os.isAlias( …pathname… )
Thanks!
Here's a version of os.path.realpath that works on Mac aliases as well as on symbolic links under Python 2:
from Carbon import File
def osx_realpath (path):
return File.FSResolveAliasFile(path, True)[0].as_pathname()
If you call osx_realpath on each directory before you recurse into it you should avoid duplication. Alternatively you could define something like
def is_osx_realpath (path):
return path == osx_realpath(path)
Here you have to worry a little about false negatives, however. If you filter for is_osx_realpath and the path you start with is an alias, your program will stop without looking at anything.
So far I don't know of a way to do this under Python 3. I have a question here where I'm hoping for an answer. Right now I can't do better than using subprocess.call to invoke something that does the check on the command line.
EDIT: I should add that not only is Carbon.File not available in Python 3, but it is deprecated and so is best avoided in Python 2 as well--however it's the most pragmatic solution I know of for Python 2 at present.
EDIT 2: here is a way to check if a file is an alias that I believe to be Python 3-friendly. However, I don't have code to resolve the alias. I believe you need PyObjC installed.
from AppKit import NSWorkspace
def is_alias (path):
uti, err = NSWorkspace.sharedWorkspace().typeOfFile_error_(
os.path.realpath(path), None)
if err:
raise Exception(unicode(err))
else:
return "com.apple.alias-file" == uti
(source)
The answer above is incorrect.
While it is true that Finder reports symlinks as alias, they are distinct things.
Symlinks are a basic feature of UNIX, but alias are a Apple only feature.
If you doubt this create a symlink to a directory and an alias. The symlink will be small typically 50-100 bytes, whereas the alias can be several MB.
os.path.islink( … ) will report symlinks, but not alias.
I am not sure how you would find them in Python, but the following link shows other methods.
https://stackoverflow.com/a/21151368/838253
You can check whether a file or directory is an alias with the GetFileInfo command in Mac OS X. GetFileInfo -aa foo prints a line with "1" if foo is an alias and "0" if not.
import subprocess
def is_alias(path):
return subprocess.check_output(["GetFileInfo", "-aa", path]) == "1\n"
Seems a little sad to spawn a process for every check, but I think this works with versions of Mac OS X since probably 10.4.4 (2006), 32-bit, 64-bit, Python 2 and Python 3. The version of GetFileInfo I have (from 2009) is a "universal" i386 + PPC binary.
GetFileInfo is part of Xcode, which is large, but you can download the command-line tools separately (see the "Separate Download" section here).
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/GetFileInfo.1.html
Old question, but I just ran into this myself.
I have no perfect method for checking if the file is an alias, however, if using mimetypes, python will return None for an alias or a symlink. Might be useful in some situations. I've only tested this in python 3.8 on macOS Big Sur.
import mimetypes
for idx, f in enumerate(filepaths):
type = mimetypes.guess_type(f)[0]
print(f"type is: {type}")
returns (without my added comments):
type is: None # <-- Folder Alias
type is: None # <-- File Alias
type is: text/x-python
type is: None # <-- Folder Alias
type is: video/mp4
type is: image/png
type is: None # <-- Folder Alias
type is: None # <-- Symlink
type is: image/png
type is: application/zip
type is: image/png
type is: image/jpeg
type is: None # <-- Symlink
I ran some files through exiftool just to see what types they returned, and aliases and symlinks both showed the following:
File Type : ALIAS
File Type Extension : alias
MIME Type : application/x-macos
You might be able to init the mimetypes for these, but haven't tested and not sure if it will give false positives if anything else shows up as application/x-macos
I have been trying to run a shell script at boot time of freebsd. I have read all simmilar questions in stackoverflow and tried. But nothing is worked. This is the sample code that i tried is dummy.
#!/bin/sh
. /etc/rc.subr
name="dummy"
start_cmd="${name}_start"
stop_cmd=":"
dummy_start()
{
echo "Nothing started."
}
load_rc_config $name
run_rc_command "$1"
Saved with name of dummy.
Permissions are -r-xr-xr-x.
in rc.conf file made dummy_enable="YES".
The problem is, when i rebooted my system to test, dummy file is not there. So script is not executing. what else need to do run my dummy script.
SRC:http://www.freebsd.org/doc/en/articles/rc-scripting/article.html#rc-flags
You need to add rcvar="dummy_enable" to your script. At least for FreeBSD 9.1.
Call your script with parameter rcvar to get the enabled status:
# /etc/rc.d/dummy rcvar
# dummy
#
dummy_enable="YES"
# (default: "")
And finally start it with parameter start - this won't start the service/script unless dummy_enable is set in /etc/rc.conf (or /etc/rc.conf.local, or /etc/defaults/rc.conf)
# /etc/rc.d/dummy start
Nothing started.
One possible explanation is that rcorder(8) says:
Within each file, a block containing a series of "REQUIRE", "PROVIDE",
"BEFORE" and "KEYWORD" lines must appear.
Though elsewhere I recall that if a file doesn't have "REQUIRE", "PROVIDE" or "BEFORE", then it will be arbitrarily placed in the dependency ordering. And, it could be that the arbitrary placement differs between the first run up to $early_late_divider and in the second run of those after $early_late_divider.
OTOH, is this a stock FreeBSD, or some variant? I recall reading that FreeNAS saves its configuration somewhere else and recreates its system files on every boot. And, quite possibly that /etc is actually on a ramdisk.
Also, /usr/local/etc/rc.d doesn't come into existence until the first port installing an rc file is installed.
I am trying to build Win32::Daemon by myself. The reason I not use CPAN is because I want to dig deeper into the working of Perl modules. In the end I hope to come up with a solution for another problem by seeing this working (not of importance here).
I would see 3 options to build the module: cygwin, mingw, microsoft compiler (cl)
On MinGW it reports that it is not supported (simple if in the Makefile.PL) which expands to more errors once I modify the check to match MinGW
On Cygwin it complains about tchar.h which, as I found out, is a Windows header (MinGW does have it).
But my real goal anyway is building it with the MS compiler, so while any compilation that does not require any special libs (like it would do with cygwin I suppose) will more.
So now here goes my nmake output from running just name /f Makefile:
NMAKE : fatal error U1073: "C:/Program" could not be created.
Stop.
I roughly translated the error message from german, but the statement is simple.
What I see here seems to be a path problem (probably the spaces). I also notice the forward slash. The Makefile was created by the Makefile.PL script (I am using Active Perl v5.12.1):
use strict;
use warnings;
use Config qw(%Config);
use ExtUtils::MakeMaker;
unless ($^O eq "MSWin32" || $^O eq "cygwin") {
die "OS unsupported\n";
}
require Win32;
my %param = (
NAME => 'Win32::Daemon',
VERSION_FROM => 'Daemon.pm',
DEFINE => '-DPERL_NO_GET_CONTEXT',
OBJECT => 'CCallbackList$(OBJ_EXT) CCallbackTimer$(OBJ_EXT) Constant$(OBJ_EXT) CWinStation$(OBJ_EXT) Daemon$(OBJ_EXT) ServiceThread$(OBJ_EXT)',
XS => { 'Daemon.xs' => 'Daemon.cpp' },
);
$param{INC} .= ' -EHsc' if $Config{'cc'} =~ /^cl/i;
$param{NO_META} = 1 if eval "$ExtUtils::MakeMaker::VERSION" >= 6.10_03;
WriteMakefile(%param);
sub MY::xs_c {
'
.xs.cpp:
$(PERL) -I$(PERL_ARCHLIB) -I$(PERL_LIB) $(XSUBPP) $(XSPROTOARG) $(XSUBPPARGS) $*.xs >xstmp.c && $(MV) xstmp.c $*.cpp
';
}
I don't know much about the MakeMaker but I don't see anything here that I could fix and would expect that it boils down to fixing the Makefile itself by hand. I tried a couple of things like quoting but nothing helped.
The thing is, I am used to problems like this when building on Windows, but normally this is for tools that were created for Unix. This one is explicitly ONLY Windows and so I would expect it to work out of the box. So I figure that I am doing something wrong.
Any help on where to find the solution?
Thanks in advance.
Edit/Addition: I tried this on another Win7 machine with Active Perl 5.16.x and it worked like a charm. I looked at the different output from this machine and the current one which fails when running perl Makefile.PL and I recieve the following output:
... Detected uninstalled Perl. Trying to continue.
Unable to find a perl 5 (by these names: C:\Program Files\Perl64\bin\perl.exe perl.exe perl5.exe perl5.12.1.exe miniperl.exe, in these dirs: . [...] C:\Program Files\Perl64\site\bin C:\Program Files\Perl64\bin [...])
Have \progra~1\perl64\lib
Want \temp\perl---please-run-the-install-script---\lib
Writing Makefile for Win32::Daemon
I truncated the output. Now please someone explain to me: Why can I run perl Makefile.PL or perl -v but it does not find my Perl in the exact directory it is in? I reinstalled it but it did not work...
Okay I finally seem to have solved this after hours of searching. The problem lies within multiple issues.
The first command of "uninstalled perl" does not make any sense to be, but you can fix it, by supplying perl Makefile.PL PERL_SRC="C\:Program Files\Perl64". Warning: This did not work in a command shell for me, I had to use powershell, because he would not treat the path correctly. You maybe need to juggle with this a bit. Note: In the end I fixed it by installing the original Active Perl, not the one provided by my installer (company software distribution)
Now to the issue of not finding perl: This is a problem with spaces in the path. I fixed this (seemingly) by creating a symlink without spaces. Now perl Makefile.PL does not throw any errors, but nmake -f "Makefile" failed. So the solution really was: Do not have spaces in your perl-path! This sucks, and quite frankfly in 2012 this shouldn't be a problem any more but here you go.
Thanks for all the effort everyone put in, this was a tough one to solve.
This example routine generates two Throw::nocatch warning messages in the kernel window. Can they be handled somehow?
The example consists of this code in a file "test.m" created in C:\Temp:
Needs["JLink`"];
$FrontEndLaunchCommand = "Mathematica.exe";
UseFrontEnd[NotebookWrite[CreateDocument[], "Testing"]];
Then these commands pasted and run at the Windows Command Prompt:
PATH = C:\Program Files\Wolfram Research\Mathematica\8.0\;%PATH%
start MathKernel -noprompt -initfile "C:\Temp\test.m"
Addendum
The reason for using UseFrontEnd as opposed to UsingFrontEnd is that an interactive front end may be required to preserve output and messages from notebooks that are usually run interactively. For example, with C:\Temp\test.m modified like so:
Needs["JLink`"];
$FrontEndLaunchCommand="Mathematica.exe";
UseFrontEnd[
nb = NotebookOpen["C:\\Temp\\run.nb"];
SelectionMove[nb, Next, Cell];
SelectionEvaluate[nb];
];
Pause[10];
CloseFrontEnd[];
and a notebook C:\Temp\run.nb created with a single cell containing:
x1 = 0; While[x1 < 1000000,
If[Mod[x1, 100000] == 0,
Print["x1=" <> ToString[x1]]]; x1++];
NotebookSave[EvaluationNotebook[]];
NotebookClose[EvaluationNotebook[]];
this code, launched from a Windows Command Prompt, will run interactively and save its output. This is not possible to achieve using UsingFrontEnd or MathKernel -script "C:\Temp\test.m".
During the initialization, the kernel code is in a mode which prevents aborts.
Throw/Catch are implemented with Abort, therefore they do not work during initialization.
A simple example that shows the problem is to put this in your test.m file:
Catch[Throw[test]];
Similarly, functions like TimeConstrained, MemoryConstrained, Break, the Trace family, Abort and those that depend upon it (like certain data paclets) will have problems like this during initialization.
A possible solution to your problem might be to consider the -script option:
math.exe -script test.m
Also, note that in version 8 there is a documented function called UsingFrontEnd, which does what UseFrontEnd did, but is auto-configured, so this:
Needs["JLink`"];
UsingFrontEnd[NotebookWrite[CreateDocument[], "Testing"]];
should be all you need in your test.m file.
See also: Mathematica Scripts
Addendum
One possible solution to use the -script and UsingFrontEnd is to use the 'run.m script
included below. This does require setting up a 'Test' kernel in the kernel configuration options (basically a clone of the 'Local' kernel settings).
The script includes two utility functions, NotebookEvaluatingQ and NotebookPauseForEvaluation, which help the script to wait for the client notebook to finish evaluating before saving it. The upside of this approach is that all the evaluation control code is in the 'run.m' script, so the client notebook does not need to have a NotebookSave[EvaluationNotebook[]] statement at the end.
NotebookPauseForEvaluation[nb_] := Module[{},While[NotebookEvaluatingQ[nb],Pause[.25]]]
NotebookEvaluatingQ[nb_]:=Module[{},
SelectionMove[nb,All,Notebook];
Or##Map["Evaluating"/.#&,Developer`CellInformation[nb]]
]
UsingFrontEnd[
nb = NotebookOpen["c:\\users\\arnoudb\\run.nb"];
SetOptions[nb,Evaluator->"Test"];
SelectionMove[nb,All,Notebook];
SelectionEvaluate[nb];
NotebookPauseForEvaluation[nb];
NotebookSave[nb];
]
I hope this is useful in some way to you. It could use a few more improvements like resetting the notebook's kernel to its original and closing the notebook after saving it,
but this code should work for this particular purpose.
On a side note, I tried one other approach, using this:
UsingFrontEnd[ NotebookEvaluate[ "c:\\users\\arnoudb\\run.nb", InsertResults->True ] ]
But this is kicking the kernel terminal session into a dialog mode, which seems like a bug
to me (I'll check into this and get this reported if this is a valid issue).