How do I change the working directory in Ada? - directory

How do I change the current working directory in Ada?
I would have expected GNAT's OS_Lib to have a chdir procedure, but no such luck.
Of course, spawning a new process running 'cd' is a hopeless endeauvour, at best it would create a new process which itself will live (very briefly) in the given directory.
with GNAT.OS_Lib;
procedure main is
procedure Spawn (Program : String) is
Empty_Arguments : GNAT.OS_Lib.Argument_List (1..0);
Exit_Code : constant Integer := GNAT.OS_Lib.Spawn (Program_Name => Program, Args => Empty_Arguments);
begin
if Exit_Code /= 0 then
raise Program_Error with Program & " exited with exit code: " & Exit_Code'Image;
end if;
end Spawn;
begin
Spawn ("cd dir"); -- replace this with the proper way to do this
Spawn ("make"); -- on windows 'dir' is another command that is dependent on the current directory
end main;
The aim is that for the next procedure, make in the above example, the directory has been changed.

You could use Set_Directory (see also RM A.16 (6)). For example:
main.adb
with Ada.Directories; use Ada.Directories;
with Ada.Wide_Text_IO; use Ada.Wide_Text_IO;
with Ada.Characters.Conversions;
procedure Main is
-- Compile with option "-gnatW8" to set wide character encoding to UTF-8.
--------------------
-- List_Directory --
--------------------
procedure List_Directory is
use Ada.Characters.Conversions;
Pattern : constant String := "*.*";
Filter : constant Filter_Type :=
(Ordinary_File => True, others => False); -- Files only.
S : Search_Type;
E : Directory_Entry_Type;
begin
Put_Line (To_Wide_String (Current_Directory));
Put_Line ("["2502"]");
Start_Search (S, Current_Directory, Pattern, Filter);
while More_Entries (S) loop
Get_Next_Entry (S, E);
if More_Entries (S) then
Put ("["251C"]["2500"] ");
else
Put ("["2514"]["2500"] ");
end if;
Put_Line (To_Wide_String (Simple_Name (E)));
end loop;
End_Search (S);
end List_Directory;
begin
List_Directory; New_Line;
Set_Directory ("./src");
List_Directory; New_Line;
Set_Directory ("../obj");
List_Directory; New_Line;
end Main;
output
$ ./obj/main
/home/deedee/foo
│
└─ default.gpr
/home/deedee/foo/src
│
└─ main.adb
/home/deedee/foo/obj
│
├─ gpsauto.cgpr
├─ main.ali
├─ main.bexch
├─ b__main.o
├─ b__main.ali
├─ main.o
├─ main.adb.stderr
├─ main.adb.stdout
├─ b__main.adb
├─ b__main.ads
└─ default-loc.xml

Related

How can I access a symbol from the linker script in my Ada code?

I am building my Ada/SPARK project using GNAT and I am using a linker script. Here is an excerpt:
SECTIONS
{
.code :
{
. = ALIGN(0x4);
*(.text.section1)
_end_of_section1 = .;
*(.text.section2)
...
}
}
The symbol _end_of_section1 is the address between the two sections. I'd like to be able to access this in my Ada code. I know it's possible in C using extern char _end_of_section1[];. Is it possible to do something like this in Ada? If not, is there some other way to get this address in the code?
You can import a linker symbol by using the Importand Link_Name aspects (see also RM B.1):
main.adb (updated on 25-jan)
with System.Storage_Elements;
with System.Address_Image;
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
package SSE renames System.Storage_Elements;
package Storage_Element_IO is
new Ada.Text_IO.Modular_IO (SSE.Storage_Element);
use Storage_Element_IO;
Start_Symbol : aliased SSE.Storage_Element
with Import, Link_Name => "_start";
Start_Symbol_Addr : constant System.Address := Start_Symbol'Address;
begin
Put ("Address : ");
Put (System.Address_Image (Start_Symbol_Addr));
New_Line;
Put ("Value : ");
Put (Start_Symbol, Base => 16);
New_Line;
end Main;
output
$ ./obj/main
Address : 0000000000403300
Value : 16#F3#
output (objdump)
$ objdump -d -M intel ./obj/main | grep -A5 "<_start>"
0000000000403300 <_start>:
403300: f3 0f 1e fa endbr64
403304: 31 ed xor ebp,ebp
403306: 49 89 d1 mov r9,rdx
403309: 5e pop rsi
40330a: 48 89 e2 mov rdx,rsp
...

How do you exit from the main procedure with an errorcode in Ada?

It seems so simple but this does not compile:
procedure Main is
begin
exit 1;
end Main;
When compiled with gprbuild, yields:
Compile
[Ada] main.adb
main.adb:3:04: cannot exit from program unit or accept statement
main.adb:3:08: missing ";"
gprbuild: *** compilation phase failed
The exit keyword in Ada clearly doesn't do what it does in other programming languages. So how do you exit from the ada main procedure with an error code?
How about:
with Ada.Command_Line;
procedure Main is
begin
Ada.Command_Line.Set_Exit_Status(Ada.Command_Line.Failure);
end Main;
Make your Ada main program a function, not a procedure, and return the exit code you want:
function Main return integer is
begin
return 1;
end Main;

Inno Setup Choose a directory to install files from a pre-defined set

In this situation, I need to install a file to specific directory, but in different computer it might be in different folder so I need to check which on is correct.
For example, I have a file and it needs to install in A folder or B folder or C folder, depends on the computer has A or B or C. So I need to check them first, if the computer has B, then install the file in the B folder, etc.
I know I can use check after file's DestDir, if the directory doesn't exist then it won't install anything, but what I need is install that file to other directory.
Thanks in advance.
In the InitializeSetup event function, check for existence of your pre-defined set of directories and remember the one you find. Then set the default installation path to the found one using a scripted constant in the DefaultDirName directive.
You will possible also want to set the DisableDirPage=yes and the UsePreviousAppDir=no.
[Setup]
DefaultDirName={code:GetDirName}
DisableDirPage=yes
UsePreviousAppDir=no
[Files]
Source: "MyProg.exe"; DestDir: "{app}"
Source: "MyProg.chm"; DestDir: "{app}"
[Code]
var
DirName: string;
function TryPath(Path: string): Boolean;
begin
Result := DirExists(Path);
if Result then
begin
Log(Format('Path %s exists', [Path]))
DirName := Path;
end
else
begin
Log(Format('Path %s does not', [Path]))
end;
end;
function GetDirName(Param: string): string;
begin
Result := DirName;
end;
function InitializeSetup(): Boolean;
begin
Result :=
TryPath('C:\path1') or
TryPath('C:\path2') or
TryPath('C:\path3');
if Result then
begin
Log(Format('Destination %s selected', [DirName]))
end
else
begin
MsgBox('No destination found, aborting installation', mbError, MB_OK);
end;
end;
Instead of using DefaultDirName={code:GetDirName}, you can also use DestDir: "{code:GetDirName}" in the respective entries of the [Files] section, if appropriate.

What is the proper way to organize a Julia source tree?

I am trying to figure the proper way to organize the source tree for a Julia application seqscan. For now I have the following tree:
$ tree seqscan/
seqscan/
├── LICENSE
├── README.md
├── benchmark
├── doc
├── examples
├── src
│   └── seq.jl
└── test
└── test_seq.jl
5 directories, 4 files
The file seq.jl contains
module SeqScan
module Seq
export SeqEntry
type SeqEntry
id
seq
scores
seq_type
end
end
end
and test_seq.jl contains:
module TestSeq
using Base.Test
using SeqScan.Seq
#testset "Testing SeqEntry" begin
#testset "test SeqEntry creation" begin
seq_entry = SeqEntry("test", "atcg")
#test seq_entry.id == "test"
#test seq_entry.seq == "atcg"
end
end
end
However, running the test code yields an error:
ERROR: LoadError: ArgumentError: Module SeqScan not found in current path.
even after setting the JULIA_LOAD_PATH environment variable to include seqscan or seqscan/src, so I must be doing something wrong?
The name of your package (the root of your local tree) needs to match the name of a file that exists under the src directory. Try this:
SeqScan/
|-- src/
|-- SeqScan.jl (your seq.jl)
I don't know why you are enclosing the module Seq in SeqScan. If there is no important reason to do that, you could access the type more directly. You could remove "module Seq" and the paired "end". Then just "using SeqScan" would bring in the type SeqEntry.
The type, SeqEntry, as written knows what to do when given four field values, one for each of the defined fields. If you want to initialize that type with just the first two fields, you need to include a two-argument constructor. For example, assuming seq is a vector of some numeric type and scores is also a vector of that numeric type and and seq_type is a numeric type:
function SeqEntry(id, seq)
seq_type = typeof(seq[1])
scores = zeros(seq_type, length(seq))
return SeqEntry(id, seq, scores, seq_type)
end
An example of a package with internal modules, for Julia v0.5.
The package is named MyPackage.jl; it incorporates two internal modules: TypeModule and FuncModule; each module has its own file: TypeModule.jl and FuncModule.jl.
TypeModule contains a new type, MyType. FuncModule contains a new function, MyFunc, which operates on variable[s] of MyType. There are two forms of that function, a 1-arg and a 2-arg version.
MyPackage uses both internal modules. It incorporates each for immediate use and initializes two variables of MyType. Then MyPackage applies MyFunc to them and prints the results.
I assume Julia's package directory is "/you/.julia/v0.5" (Windows: "c:\you.julia\v0.5"), and refer to it as PkgDir. You can find the real package directory by typing Pkg.dir() at Julia's interactive prompt. The first thing to do make sure Julia's internal information is current: > Pkg.update() and then get a special package call PkgDev: > Pkg.add("PkgDev")
You might start your package on GitHub. If you are starting it locally, you should use PkgDev because it creates the essential package file (and others) using the right structure:
> using PkgDev then > PkgDev.generate("MyPackage","MIT")
This also creates a file, LICENSE.md, with Julia's go-to license. You can keep it, replace it or remove it.
In the directory PkgDir/MyPackage/src, create a subdirectory "internal". In the directory PkgDir/MyPackage/src/internal, create two files: "TypeModule.jl" and "FuncModule.jl", these:
TypeModule.jl:
module TypeModule
export MyType
type MyType
value::Int
end
end # TypeModule
FuncModule.jl:
module FuncModule
export MyFunc
#=
!important!
TypeModule is included in MyPackage.jl before this module
This module gets MyType from MyPackage.jl, not directly.
Getting it directly would create mismatch of module indirection.
=#
import ..MyPackage: MyType
function MyFunc(x::MyType)
return x.value + 1
end
function MyFunc(x::MyType, y::MyType)
return x.value + y.value + 1
end
end # FuncModule
And in the src directory, edit MyPackage.jl so it matches this:
MyPackage.jl:
module MyPackage
export MyType, MyFunc
#=
!important! Do this before including FuncModule
because FuncModule.jl imports MyType from here.
MyType must be in use before including FuncModule.
=#
include( joinpath("internal", "TypeModule.jl") )
using .TypeModule # prefix the '.' to use an included module
include( joinpath("internal", "FuncModule.jl") )
using .FuncModule # prefix the '.' to use an included module
three = MyType(3)
five = MyType(5)
four = MyFunc(three)
eight = MyFunc(three, five)
# show that everything works
println()
println( string("MyFunc(three) = ", four) )
println( string("MyFunc(three, five) = ", eight) )
end # MyPackage
Now, running Julia entering > using MyPackage should show this:
julia> using MyPackage
4 = MyFunc(three)
9 = MyFunc(three, five)
julia>

Inno Script: Strange Empty Folder

My Inno Script installer makes an empty folder in the C: drive but only on one machine. Every other machine I've tested the script on works without this problem. I've tested on two Windows 7 computers, an XP computer and a Windows XP virtual computer. For all of these computers the installer doesn't create this empty folder.
However, on my colleague's Windows XP computer the installer behaves as it should except that it also creates an empty directory on the C Drive. Uninstalling does not remove the folder.
I've had a look through my script and looked for things that could possibly be creating the extra folder, but I can't see anything. It's especially hard to solve because I can't seem to replicate the problem.
Does anyone here have an idea of why this could be happening?
#define MyAppName "Program1"
#define MyAppVersion "1.0"
#define MyAppExeName "program1.exe"
[Setup]
AppName=Test
AppVersion=1.0
AppPublisher=Me
AppSupportURL=www.google.com
AppUpdatesURL= www.google.com
DefaultDirName={code:getDirectory}
UsePreviousAppDir=no
DisableDirPage=yes
DefaultGroupName={#MyAppName}
DisableProgramGroupPage=yes
OutputBaseFilename={#MyAppName} {#MyAppVersion} Setup
Compression=lzma
SolidCompression=yes
OutputDir=output
UninstallFilesDir={code:getDirectory}
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
[Files]
Source: "test.iss"; DestDir: "{code:getDirectory}"; Flags: ignoreversion;
[Code]
var
InstallTestVersionCheckBox: TNewCheckBox;
Directory : string;
// ------------------------------
// INSTALL
// ------------------------------
procedure InitializeWizard;
var
MainPage: TWizardPage;
begin
MainPage := CreateCustomPage(wpWelcome, 'text', 'text');
// make the checkbox
InstallTestVersionCheckBox := TNewCheckBox.Create(MainPage);
InstallTestVersionCheckBox.Parent := MainPage.Surface;
InstallTestVersionCheckBox.Caption := 'Test Version';
end;
function InstallTestVersion: Boolean;
begin
Result := InstallTestVersionCheckBox.Checked;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if InstallTestVersion() then
begin
// Set the test version directory
Directory := ExpandConstant('{pf32}\Testversion');
end
else
begin
// Set the production version directory
Directory := ExpandConstant('{pf32}\Normal');
end;
end;
// Returns the correct directory
function getDirectory(Param: String): String;
begin
Result := Directory;
end;
For those who might run into similar problems: Inno setup suddenly created additional empty folders I didn't want to have. Finally I understood the reason: I tried to create a single empty folder within the [Files] section. That was no good idea... So you just create your empty folder with the [Dirs] section to do it the good way.
DO NOT DO THIS:
[Files]
Source: "M:\My_Empty_Folder"; DestDir: "{userdocs}\My_App_Name"; Flags: ignoreversion
THIS IS BETTER:
[Dirs]
Name: "{userdocs}\My_App_Name\My_Empty_Folder"

Resources