How do I check the OS in the F# preprocessor? - f#

We're multiple persons working on the same F# project. Some use MacOS and Visual Studio Code together with Ionide while others use Windows with Visual Studio. In the F#-code, we need to access some files, but MacOS uses / to specify paths while Windows uses \. In F#, how can we make something like:
#if OS_WINDOWS
let path = "path\to\file.txt"
#elif OS_MAC
let path = "path/to/file.txt"
#endif

There is no built-in pre-defined symbol to indicate what operating system you are compiling for. When you use .NET, you generally use the same compiled assembly on all operating systems, so this is not something that you can reasonably do in a pre-processor anyway.
You can check what OS are you running on at runtime using System.Environment:
open System
let path =
if Environment.OSVersion.Platform = PlatformID.Win32NT then #"path\to\file.txt"
else #"path/to/file.txt"
That said, if your only concern is slashes and backslashes in a path, you can just use:
let path = System.IO.Path.Combine("path", "to", "file.txt")

Related

Documentation/List of standard preprocessing symbols

As an example, I'm using the following preprocessing directive
#if COMPILED
let context = Sql.GetDataContext(ConfigurationManager.ConnectionStrings.[AppDB].ConnectionString)
#else
let context = Sql.GetDataContext()
#endif
so that I'm able to test a dll library from F# interactive, to give you an idea
#I #"bin\Debug"
#r #"import.dll"
#r #"FSharp.Data.SqlProvider.dll"
#load "Library1.fs"
open SqlLib
open SqlDB
// Define your library scripting code here
let book = "My Company"
let db = DB()
db.analysts book |> Array.iter (printfn "%A")
because, of course, in the example above ConfigurationManager would not be usable from the scripting engine, so I need to implement a change at preprocessing time.
More generally, where can I find the documentation or a at least a list of all the available, standard symbols, that are already automatically defined, including COMPILED and so on...?
From Compiler directives F#:
Symbols that you use in the if directive must be defined by the command line or in the project settings; there is no define preprocessor directive...
When VERSION1 is defined by using the -define compiler option, the code between the #if directive and the #else directive is activated. Otherwise, the code between #else and #endif is activated.
So you can defined your own preprocessor directives when compile code. If you work with .NET Core, inside fsproj or csproj you can define these symbols as:
<PropertyGroup Condition="'$(TargetFramework)' != 'net40'">
<DefineConstants>NET45</DefineConstants>
</PropertyGroup>
dotnet sends them to fsc. If you curious what symbols are defined by default, you can investigate fsc source code
I found COMPILED and INTERACTIVE there.

How can I locate a file to use with the system/child_process API within a Firefox add-on?

I would like to write a Firefox add-on that communicates with a locally installed program to exchange data. It looks like this can be done using either js-ctypes or the low-level system/child_process API, with the latter being the recommended solution.
The child_process API appeals because it sends and receives data abstractly over a pipe rather than directly at the C interface level. However, to use it you need (it seems) to supply the full path to the executable within your code:
var child_process = require("sdk/system/child_process");
var ls = child_process.spawn('/bin/ls', ['-lh', '/usr']);
In my case, the executable is installed by another application and we don't know it's exact location - it will differ according to OS, the user's drives, and possibly the user's preference. I imagine this problem will be common to most executables that are not built in to the OS. So my question is: what means do I have to locate the full path of the executable I want to use? I will need to support multiple OSes but presumably could have different solutions for each if needed.
Thanks!
Here's the code I used on Windows - the key was being able to read an environment variable to find the location of the appropriate application folder. After that I assume that my application is stored under a well-known subpath (we don't allow customization of it).
var system = require("sdk/system");
var iofile = require('sdk/io/file');
var child_process = require('sdk/system/child_process');
var progFilesFolder = system.env["programfiles(x86)"],
targetFile = iofile.join(progFilesFolder, 'FolderName', 'Program.exe');
targetFileExists = iofile.exists(targetFile);
if (targetFileExists) {
var p = child_process.spawn(targetFile);
}
I haven't written the code for Mac yet but I expect it to be similar, with the difference being that there are no drive letters to worry about and the system folders in OS X have standard names (even on localized systems).

AddPrinterDriverEx fails if pscript5.dll not in root drivers folder

I've got some code to install a post-script based virtual printer with a port monitor (for printing to PDF). The code works fine on x86 and x64 platforms from WinXP to Win7, unless the PScript5 set of files isn't in the "root" drivers folder. On a few of my test PCs the files were already there, but on a newer Win7 PC I have the files were not already there.
For example, since I know the above is clear as mud, on Windows XP 32-bit, if these files:
ps5ui.dll
pscript5.dll
pscript.hlp
pscript.ntf
Are located in c:\windows\system32\spool\drivers\w32x86\, then my code works. If they aren't, my code fails. The files are always in c:\windows\system32\spool\drivers\w32x86\3\, and the outcome is the same (apparently Windows doesn't look in the "3" sub-folder).
Do I need to copy them from the 3 sub-folder -- is this what others are doing? Doesn't seem like "good practice" for some reason. According to this on MSDN, I can maybe redistribute the files, but I need to contact Microsoft I guess, and I can't figure out how to do that (links are weird, typical).
This is my (cleaned up) code as it runs on Win7 64-bit (32-bit just uses "Windows NT x86" instead of "Windows x64"):
DRIVER_INFO_3 di;
memset(&di,0,sizeof(di));
di.cVersion = 3;
di.pName = "My PDF Printer";
di.pEnvironment = "Windows x64";
di.pDriverPath = "pscript5.dll";
di.pDataFile = "mypdf.ppd";
di.pConfigFile = "ps5ui.dll";
di.pHelpFile = "pscript.hlp";
di.pDependentFiles = "pscript.ntf\0\0";
di.pMonitorName = NULL;
di.pDefaultDataType = "RAW";
if(!AddPrinterDriverEx(NULL,3,(BYTE*)&di,APD_COPY_ALL_FILES|APD_INSTALL_WARNED_DRIVER))
{
char err[1024];
sprintf(err,"Error adding printer driver: 0x%08X",GetLastError());
Prompt(err);
return;
}
AddPrinterDriverEx fails with error code 2, file not found, if any of the above files are not in the root folder. If I copy the files from the "3" sub-folder and then run the exact code again, it works. I've tried without the APD_COPY_ALL_FILES flag also, same error (2) if files not found, and some other error if they are there (I assume an error code meaning files already exist, shouldn't matter as not related to real issue anyway).
You don't need to contact Microsoft; you can freely redistribute the PScript5 files. However, to use AddPrinterDriverEx you must ensure that all required files are in the \windows\system32\spool\drivers\w32x86 folder, and you shouldn't assume they'll be in the \windows\system32\spool\drivers\w32x86\3 folder to copy from. You should provide a copy of them with your installer and copy them there yourself before calling AddPrinterDriverEx.
Are you sure you can freely redistribute the pscript5 files?
According to this article from Xeros you must ask to Microsoft to redistribute them:
Other manufacturers such as Xerox can obtain redistribution rights
for this file and can then incorporate this DLL with their software
applications and print drivers for Microsoft operating systems.

How can I get F# Interactive window to use the same path as the project?

In my project I am opening a file with some relative path to the executable. I was trying to test my code in the F# Interractive window, but it seems to run from a completely different path. How can I change the path/ make it run from the same path as the project?
I think __SOURCE_DIRECTORY__ identifier could help here.
You should use compiler directives to separate between using F# Interactive and compiling F# project.
#if INTERACTIVE
let path = __SOURCE_DIRECTORY__ + some_relative_path
#else
let path = another_relative_path
#endif
You could set the current working directory when running in FSI:
#if INTERACTIVE
System.IO.Directory.SetCurrentDirectory("<project_path>")
#endif

Lua return directory path from path

I have string variable which represents the full path of some file, like:
x = "/home/user/.local/share/app/some_file" on Linux
or
x = "C:\\Program Files\\app\\some_file" on Windows
I'm wondering if there is some programmatic way, better then splitting string manually to get to directory path
How do I return directory path (path without filename) in Lua, without loading additional library like LFS, as I'm using Lua extension from other application?
In plain Lua, there is no better way. Lua has nothing working on paths. You'll have to use pattern matching. This is all in the line of the mentality of offering tools to do much, but refusing to include functions that can be replaced with one-liners:
-- onelined version ;)
-- getPath=function(str,sep)sep=sep or'/'return str:match("(.*"..sep..")")end
getPath=function(str,sep)
sep=sep or'/'
return str:match("(.*"..sep..")")
end
x = "/home/user/.local/share/app/some_file"
y = "C:\\Program Files\\app\\some_file"
print(getPath(x))
print(getPath(y,"\\"))
Here is a platform independent and simpler solution based on jpjacobs solution:
function getPath(str)
return str:match("(.*[/\\])")
end
x = "/home/user/.local/share/app/some_file"
y = "C:\\Program Files\\app\\some_file"
print(getPath(x)) -- prints: /home/user/.local/share/app/
print(getPath(y)) -- prints: C:\Program Files\app\
For something like this, you can just write your own code. But there are also libraries in pure Lua that do this, like lua-path or Penlight.

Resources