bjam - cannot assign a literal to a variable? - bjam

Well, this must be the most stupid and idiotic behavior I've seen from a programming language.
https://www.bfgroup.xyz/b2/manual/release/index.html says:
Syntactically, a Boost.Jam program consists of two kinds of
elements—keywords (which have a special meaning to Boost.Jam) and
literals. Consider this code:
a = b ;
which assigns the value b to the variable a. Here, = and ; are
keywords, while a and b are literals.
⚠ All syntax elements, even
keywords, must be separated by spaces. For example, omitting the space
character before ; will lead to a syntax error.
If you want to use a literal value that is the same as some keyword,
the value can be quoted:
a = "=" ;
OK, so far so good. So I have this in my Jamroot:
import path : basename ;
actions make_mytest_install
{
echo "make_mytest_install: MY_ROOT_PATH $(MY_ROOT_PATH) PWD $(PWD:E=not_set)" ;
epath = "$(MY_ROOT_PATH)/projects/mytest/bin/gcc-9/release/qt5client" ;
ename = basename ( $(epath) ) ;
echo "epath $(epath) ename $(ename)" ;
}
explicit install-gettext ;
make install-mytest : : #make_mytest_install ;
... and I try this:
bjam install-mytest
...updating 1 target...
Jamfile</home/USER/src/myproject>.make_mytest_install bin/install-mytest
make_mytest_install: MY_ROOT_PATH /home/USER/src/myproject PWD not_set
[ SHELL pstree -s -p 2720269 && echo PID 2720269 PWD /home/USER/src/myproject ]
/bin/sh: 13: epath: not found
/bin/sh: 14: Syntax error: "(" unexpected
.....
...failed Jamfile</home/USER/src/myproject>.make_mytest_install bin/install-mytest...
...failed updating 1 target...
Now - how come that the SIMPLEST assignment to a string, EXACTLY AS in the manual:
epath = "$(MY_ROOT_PATH)/projects/mytest/bin/gcc-9/release/qt5client" ;
... fails, and this variable cannot be found anymore?
What is the logic in this? How the hell is this supposed to work? I would get it if MY_ROOT_PATH was undefined - but the echo before it, shows that it is not? What is this lunacy?
So I cannot believe I'm asking something this trivial, but:
How do you assign a string to a variable in bjam language?

Well, the error gives somewhat of a hint: /bin/sh: -> so apparently inside actions, it is sh that runs - then again, if it was really sh I could have assigned variables, but I can't. So best I could do, was to remove the assignments OUT of actions:
import path : basename ;
epath = "$(MY_ROOT_PATH)/projects/mytest/bin/gcc-9/release/qt5client" ;
# ename = basename ( $(epath) ) ; # nope, causes target install-mytest to not be found :(
# calling a shell for basename works - but adds a damn NEWLINE at end!?!?!?!
ename = [ SHELL "basename $(epath)" ] ;
actions make_mytest_install
{
echo "make_mytest_install: MY_ROOT_PATH $(MY_ROOT_PATH) PWD $(PWD:E=not_set)" ;
echo "epath $(epath) ename $(ename)" ;
}
explicit install-mytest ;
make install-mytest : : #make_mytest_install ;
So, assignment kind of passes, but you still can't get the basename ?!
I still don't understand, who thought this kind of variable management is a good idea ... I don't even understand, how people managed to build stuff with this system

Related

zsh: How to test for existence of two programs on zsh use $+commands

In zsh we can test for the existence of a progragram using this:
(( $+commands[program] )) && program
My question is: How to use commands for testing the existence of two programs instead one?
Found this under Subscript Flags in man 1 zshparam (portions removed, emphasis added):
r if this flag is given, the exp is taken as a pattern
i Like r,
I Like i, but gives the index of the last match, or all possible matching keys in an associative array. On failure substitutes 0, or the empty string for an associative array. This flag is best when testing for values or keys that do not exist.
So to test for both program1 and program2, you can do:
(( $#commands[(I)(program1|program2)] == 2 ))
I guess you could just use the following:
if ((( $+commands[program1] ) && ( $+commands[program2] ))); then
echo 'both command exists'
fi
the same could be done using bash:
if [[ `command -v program1` && `command -v program2`]]; then
echo 'both command exists'
fi
I figured out one way of solving this issue:
alias rm='echo use trash instead!'
(( $+commands[trash] && $+commands[gio] )) && alias trash='gio trash'
I still would like to know if it is possible to use something like:
(( $+commands[program1 program2] ))

zsh completion complete literal quotes

I am writing my own completions for a program.
I would like to be able to complete quoted words, maintaining the double or single quotes in the completion.
#compdef foo
_foo {
local strings
strings=(\
foo\
bar\
'spam eggs')
_arguments \
{-s,--string}'[Select a string]:STR:(\""${strings[#]}"\")\
&& return 0
}
_foo
what I'd expect:
foo -s <TAB>
"foo" "bar" "spam eggs"
what it get:
\"foo\" \"bar\" \"spam\ eggs\"
I ended up trying different combinations of nested quotes and escapes almost brainlessly but with no luck, as I was not able to find the relevant docs (really, zsh docs are "dense")
Thank you!

How to create a new directory from Force Fortran 2.0

I need to create a new directory from my code to be able to write a data file to it.
I am using Force Fortran 2.0 from Windows 8 and I am also wondering if this syntax is going to vary from one operating system to the other due to the front/backslash issue.
Force Fortran uses older compilers (g77, g95, gfortran [unknown version]), so I'll present a solution with system. For compilers that support it, it's better to use the Standard-conforming EXECUTE_COMMAND_LINE.
You can simply use mkdir, which is present on both Windows and Unix machines. By default, mkdir creates the folder and (non-existing) parent folders on Windows. This has to be explicitly given on Unix (-p). Using system you can execute this from Fortran:
program test
implicit none
#ifdef _WIN32
character(len=*),parameter :: MKDIR = 'mkdir '
! ^
! The blank is intentional!
#else
character(len=*),parameter :: MKDIR = 'mkdir -p '
! ^
! The blank is intentional!
#endif
integer :: stat
stat = system( MKDIR // 'testFolder' )
if ( stat /= 0 ) then
print *, 'mkdir: failed to create folder! '
endif
end program
You still need to create a routine that takes care of the correct folder delimiter, here is a quick&dirty example:
module conv_mod
contains
function conv2win(str) result(res)
implicit none
character(len=*),intent(in) :: str
character(len=len(str)) :: res
integer :: i
res = str
do i=1,len(res)
if ( res(i:i) == '/' ) res(i:i) = '\'
enddo ! i
end function
function conv2unix(str) result(res)
implicit none
character(len=*),intent(in) :: str
character(len=len(str)) :: res
integer :: i
res = str
do i=1,len(res)
if ( res(i:i) == '\' ) res(i:i) = '/'
enddo ! i
end function
end module
program conv
use conv_mod
print *,conv2win('some/path')
print *,conv2win('some\path')
print *,conv2unix('some\path')
end program
This doesn't take care of things like C:\, though... As #VladimirF noted, you can use / in Windows, too. You would still need to convert the backslash to / in Unix.

Store in a variable the result of a shell as Int

So I work with files, and I need to know the largest line in file X. Using Unix awk results in a Int that I'm looking for. But in Haskell how can I return that value and save it to a variable?
I tried define something with IO [Int] -> [Int]
maxline = do{system "awk ' { if ( length > x ) { x = length } }END{ print x }' filename";}
doesn't work cause:
Couldn't match expected type 'Int',against inferred type 'IO GHC.IO.Exception.ExitCode'
This is because the system action returns the exit status of the command you run which cannot be converted to Int. You should use the readProcess to get the commands output.
> readProcess "date" [] []
"Thu Feb 7 10:03:39 PST 2008\n"
Note that readProcess does not pass the command to the system shell: it runs it directly. The second parameter is where the command's arguments should go. So your example should be
readProcess "awk" [" { if ( length > x ) { x = length } }END{ print x }", "/home/basic/Desktop/li11112mp/textv"] ""
You can use readProcess to get another program's output. You will not be able to convert the resulting IO String into a pure String; however, you can lift functions that expect Strings into functions that expect IO Strings. My two favorite references for mucking about with IO (and various other monads) are sigfpe's excellent blog posts, You Could Have Invented Monads! (And Maybe You Already Have.) and The IO Monad for People who Simply Don't Care.
For this particular problem, I would strongly suggest looking into finding a pure-Haskell solution (that is, not calling out to awk). You might like readFile, lines, and maximumBy.

side effect of zsh echo?

For some reason this script will work with all of the 'echo's at the end, but without them $wall is an empty string. This seems like really odd behaviour.
#!/bin/zsh
if [ ! -n "$1" ] ; then
files=(~/pictures/backgrounds/*jpg)
else
while [ $1 ] ; do
files+=(`echo $1/*jpg`)
shift
done
fi
echo $files
N=${#files}
echo $N
((N=RANDOM%N))
echo $N
wall=${files[$N]}
echo $wall
cp $wall ~/wall.jpg
This code will sometimes fail because RANDOM%N can result in zero and zsh array indexes start with 1. You should use RANDOM%N+1 instead.
You can:
setopt ksharrays
to enable zero-based indexing.
From man zshoptions:
Emulate ksh array handling as closely as possible. If this
option is set, array elements are numbered from zero, an array
parameter without subscript refers to the first element instead
of the whole array, and braces are required to delimit a sub‐
script (${path[2]}' rather than just$path[2]').

Resources