Why file path string is not splitting - string

I want to find files in a directory, then split the pathname and print each part of path on a separate line:
(Directory working: '.')
allFilesMatching: '*.st' do: [ :ff | (ff name)
findTokens: '/' "Linux separator"
"splitOn: '/' -this also does not work"
do: [ :i|
i displayNl ]]
However it is giving following error:
$ gst firstline.st
"Global garbage collection... done"
Object: '/home/abcd/firstline.st' error: did not understand #findTokens:do:
MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
String(Object)>>doesNotUnderstand: #findTokens:do: (SysExcept.st:1448)
optimized [] in UndefinedObject>>executeStatements (firstline.st:3)
[] in Kernel.RecursiveFileWrapper(FilePath)>>filesMatching:do: (FilePath.st:903)
[] in Kernel.RecursiveFileWrapper>>namesDo:prefixLength: (VFS.st:378)
[] in File>>namesDo: (File.st:589)
BlockClosure>>ensure: (BlkClosure.st:268)
File>>namesDo: (File.st:586)
Kernel.RecursiveFileWrapper>>namesDo:prefixLength: (VFS.st:373)
Kernel.RecursiveFileWrapper>>namesDo: (VFS.st:396)
Kernel.RecursiveFileWrapper(FilePath)>>filesMatching:do: (FilePath.st:902)
File(FilePath)>>allFilesMatching:do: (FilePath.st:775)
Directory class>>allFilesMatching:do: (Directory.st:225)
UndefinedObject>>executeStatements (firstline.st:2)
The error message is really long and complex!
Both findTokens and splitOn are not working.
Where is the problem and how can this be solved.

The message maybe long but the line says the reason:
Object: '/home/abcd/firstline.st' error: did not understand #findTokens:do
You probably want to use a split differently, probably using subStrings: $character. I just tried it on GNU Smalltalk windows version:
The command:
'C:\prg_sdk\GNU Smalltalk(x86)\share\smalltalk\unsupported\torture.st' subStrings: $\
The result:
OrderedCollection ('C:' 'prg_sdk' 'GNU Smalltalk(x86)' 'share' 'smalltalk' 'unsupported' 'torture.st' )
Where you get your path when you have it in the collection. You start either from beginning or end.
For example you can start from beginning like this:
resultPath := nil.
pathCollection := 'C:\prg_sdk\GNU Smalltalk(x86)\share\smalltalk\unsupported\torture.st' subStrings: $\.
pathCollection do: [ :eachPartPath |
resultPath := (resultPath isNil) ifTrue: [
eachPartPath
] ifFalse: [
resultPath, '\', eachPartPath
].
resultPath displayNl
]

Related

xgettext - How to extract strings split by nulls

There's an issue in extracting strings (with xgettext) from gst-plugins-base where a string has null delimiters -
static const gchar genres[] =
"Blues\000Classic Rock\000Country\000Dance\000Disco\000Funk\000Grunge\000"
"Hip-Hop\000Jazz\000Metal\000New Age\000Oldies\000Other\000Pop\000R&B\000"
"Rap\000Reggae\000Rock\000Techno\000Industrial\000Alternative\000Ska\000"
"Death Metal\000Pranks\000Soundtrack\000Euro-Techno\000Ambient\000Trip-Hop"
"\000Vocal\000Jazz+Funk\000Fusion\000Trance\000Classical\000Instrumental\000"
"Acid\000House\000Game\000Sound Clip\000Gospel\000Noise\000Alternative Rock"
"\000Bass\000Soul\000Punk\000Space\000Meditative\000Instrumental Pop\000"
"Instrumental Rock\000Ethnic\000Gothic\000Darkwave\000Techno-Industrial\000"
"Electronic\000Pop-Folk\000Eurodance\000Dream\000Southern Rock\000Comedy"
"\000Cult\000Gangsta\000Top 40\000Christian Rap\000Pop/Funk\000Jungle\000"
"Native American\000Cabaret\000New Wave\000Psychedelic\000Rave\000Showtunes"
"\000Trailer\000Lo-Fi\000Tribal\000Acid Punk\000Acid Jazz\000Polka\000"
"Retro\000Musical\000Rock & Roll\000Hard Rock\000Folk\000Folk/Rock\000"
"National Folk\000Swing\000Bebob\000Latin\000Revival\000Celtic\000Bluegrass"
"\000Avantgarde\000Gothic Rock\000Progressive Rock\000Psychedelic Rock\000"
"Symphonic Rock\000Slow Rock\000Big Band\000Chorus\000Easy Listening\000"
"Acoustic\000Humour\000Speech\000Chanson\000Opera\000Chamber Music\000"
"Sonata\000Symphony\000Booty Bass\000Primus\000Porn Groove\000Satire\000"
"Slow Jam\000Club\000Tango\000Samba\000Folklore\000Ballad\000Power Ballad\000"
"Rhythmic Soul\000Freestyle\000Duet\000Punk Rock\000Drum Solo\000A Capella"
"\000Euro-House\000Dance Hall\000Goa\000Drum & Bass\000Club-House\000"
"Hardcore\000Terror\000Indie\000BritPop\000Negerpunk\000Polsk Punk\000"
"Beat\000Christian Gangsta Rap\000Heavy Metal\000Black Metal\000"
"Crossover\000Contemporary Christian\000Christian Rock\000Merengue\000"
"Salsa\000Thrash Metal\000Anime\000Jpop\000Synthpop";
I'm using xgettext-0.21 to extract the strings -
xgettext -a --no-wrap ./gst-libs/gst/tag/gstid3tag.c -o -
I'm getting only one of the strings -
#: gst-libs/gst/tag/gstid3tag.c:51
msgid "Blues"
msgstr ""
While I should get also "Classic Rock", "Country", "Dance", etc...
Is there any other way to extract those strings? Maybe some other tool or by using specific flags with the xgettext command?
There is no way to extract this string with xgettext and that is by design. And even if there was a way, there are no tools available to edit po file with entries containing null bytes.
The solution is to assemble the string with the null bytes at runtime or compile time. The latter would require a helper script that generates the source file containing the genre list.
An example in Perl:
#! /usr/bin/env perl
use strict;
# Stub gettext that just returns the argument.
sub gettext {
shift;
}
my $genres = join '\\000', (
gettext('Blues'),
gettext('Classic Rock'),
gettext('Country'),
gettext('Dance'),
);
print <<EOF;
static const gchar genres[] = "$genres";
EOF
Running the script will produce the required snippet in C. And feeding it as an additional source file to xgettext will add all genres to your po file:
$ xgettext --omit-header -o - genres.pl
#: genres.pl:11
msgid "Blues"
msgstr ""
#: genres.pl:12
msgid "Classic Rock"
msgstr ""
#: genres.pl:13
msgid "Country"
msgstr ""
#: genres.pl:14
msgid "Dance"
msgstr ""
You can do that, of course, in every other language that xgettext supports, not just in Perl. Pick the one that is easiest to integrate into your build system.
Just using a different delimiter (for example "Blues:Classic Rock:...") not only has escaping issues but would also result in a po file that is awkward to translate.

How to allocate a value that changes while execution in vim (lightline plugin)?

I'm hacking on the lightline plugin of vim (downloaded version). I can modify the colors of each themes. I did something that works well in the powerline.vim scheme (path : ~/.vim/pack/plugins/start/lightline/autoload/lightline/colorscheme/powerline.vim)
Now I want the colortheme to change while I'm in vim. I added this code in the begining of powerline.vim :
10 let s:BSsplitscolor = "'darkestgreen', 'brightgreen'"
11 if g:BSsplitsbool == "1"
12 let s:BSsplitscolor = "'gray4', 'brightorange'"
13 endif
14
15 " ============================== NOTE: below : already there
16
17 let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}}
18 let s:p.normal.left = [ [s:BSsplitscolor, 'bold'], ['white', 'gray4'] ]
Here s:BSsplitscolor contains the colors I want : it's either 'gray4', 'brightorange' if g:BSsplitsbool equals 1 or 'darkestgreen', 'brightgreen' if not. It's g:BSsplitsbool that changes.
Now the problem is at the 16th line : when I add s:BSsplitscolor after [ [, I get these errors when I restart vim (translate from french) :
Error detected while treating functionlightline#update[5]..lightline#colorscheme[18]..lightline#highlight :
line 18 :
E254: can not allocate color darkestgreen
E416: missing '=' : , 'brightgreen' guibg=bold ctermfg=0 ctermbg=0
Error detected while treating function lightline#update :
line 5 :
E171: missing :endif
I think I'm missing something... I'm not so good at vim scripting : I can do an if instruction, remap, and that's all.
First, the solution:
let s:BSsplitscolor = ['darkestgreen', 'brightgreen']
[...]
let s:p.normal.left = [ s:BSsplitscolor + ['bold'], ['white', 'gray4'] ]
Second, the explanation:
You are trying to build a list of three items:
['darkestgreen', 'brightgreen', 'bold']
out of a string that vaguely looks like a list:
"'darkestgreen', 'brightgreen'"
and a list with a single string:
['bold']
by inserting that string in that list:
[ s:BSsplitscolor, 'bold']
which gives you this monstrosity:
['''darkestgreen'', ''brightgreen''', 'bold']
which is a list of two items, not at all what you are trying to build. I'm not aware of a scripting language where something like that could be expected to work.
The actual solution is to make s:BSsplitscolor a list:
let s:BSsplitscolor = ['darkestgreen', 'brightgreen']
and merge it with ['bold']. This can be done in several ways. With :help expr-+:
let s:p.normal.left = [ s:BSsplitscolor + ['bold'], ['white', 'gray4'] ]
or with :help extend():
let s:p.normal.left = [ extend(s:BSsplitscolor, ['bold']), ['white', 'gray4'] ]

RBParser message nodes and targeting the receiver and the argument?

Trying to get some of my old code up and running in Pharo. Some method names are different but after some hardship I managed to find equivalents that work.
I am parsing my code and I'd like to check if the receiver or any of the arguments is aSymbol in an effort to match them to supported alternatives. I've managed to do this to selectors, by analysing RBMessageNode s
aNode selector == aSymbol ifTrue: [ aNode selector: replacementSymbol ].
How can this be done to arguments and receivers? Is there a comprehensive guide on RBParser somewhere?
By direct manipulation
Assuming that you are looking for cases like this:
aSymbol message: aSymbol message: aSymbol
For receiver you should do:
(aNode isMessage and: [
aNode receiver isVariable and: [
aNode receiver name = 'aSymbol' ]]) ifTrue: [
"do your job here" ]
Here is another example on how to replace #aSymbol arguments with #newSymbol:
messageNode arguments: (messageNode arguments collect: [ :arg |
(arg isLiteralNode and: [ arg value = #aSymbol ])
ifFalse: [ arg ]
ifTrue: [ | newNode |
newNode := #aNewSymbol asLiteralNode.
arg replaceSourceWith: newNode.
newNode ] ]).
methodClass compile: ast newSource
The replaceSourceWith: makes sure that just a source will be replaced, but for newSource to actually return a new source you also need to swap the nodes themselves, that's why I'm doing a collect on arguments and return the new ones where needed.
You can view help about RBParser in Word Menu > Help > Help Browser > Refactoring Framework.
You can also play around by inspecting
RBParser parseExpression: 'aSymbol message: aSymbol message: aSymbol'
and looking at its contents
By Parse Tree Transformation
You can use pattern code to match and replace certain code. For example to change the symbol argument of a perform: message you can do this:
ast := yourMethod parseTree.
rewriter := RBParseTreeRewriter new
replace: '`receiver perform: #aSymbol'
with: '`receiver perform: #newSelector'.
(rewriter executeTree: ast) ifTrue: [
yourMethod class compile: ast newSource ]
You can learn more about the pattern matching syntax in the help topic Word Menu > Help > Help Browser > Refactoring Framework > Refactoring Engine > RBPatternParser …. I thing that MatchTool from pharo catalog can greatly help you in testing the match expressions (it also has a dedicated help topic about the matching syntax) while RewriteTool can help you to preview how your code will be transformed.

AC_ARG_ENABLE in an m4_foreach_w loop: no help string

I wish to generate a lot of --enable-*/--disable-* options by something like:
COMPONENTS([a b c], [yes])
where the second argument is the default value of the automatic enable_* variable. My first attempt was to write an AC_ARG_ENABLE(...) within an m4_foreach_w, but so far, I'm only getting the first component to appear in the ./configure --help output.
If I add hand-written AC_ARG_ENABLEs, they work as usual.
Regardless, the --enable-*/--disable-* options work as they should, just the help text is missing.
Here's the full code to reproduce the problem:
AC_INIT([foo], 1.0)
AM_INIT_AUTOMAKE([foreign])
AC_DEFUN([COMPONENTS],
[
m4_foreach_w([component], [$1], [
AS_ECHO(["Processing [component] component with default enable=$2"])
AC_ARG_ENABLE([component],
[AS_HELP_STRING([--enable-[]component], [component] component)],
,
[enable_[]AS_TR_SH([component])=$2]
)
])
AC_ARG_ENABLE([x],
[AS_HELP_STRING([--enable-[]x], [component x])],
,
[enable_[]AS_TR_SH([x])=$2]
)
AC_ARG_ENABLE([y],
[AS_HELP_STRING([--enable-[]y], [component y])],
,
[enable_[]AS_TR_SH([y])=$2]
)
])
COMPONENTS([a b c], [yes])
for var in a b c x y; do
echo -n "\$enable_$var="
eval echo "\$enable_$var"
done
AC_CONFIG_FILES(Makefile)
AC_OUTPUT
And an empty Makefile.am. To verify that the options work:
$ ./configure --disable-a --disable-b --disable-d --disable-x
configure: WARNING: unrecognized options: --disable-d
...
Processing component a with default enable=yes
Processing component b with default enable=yes
Processing component c with default enable=yes
$enable_a=no
$enable_b=no
$enable_c=yes
$enable_x=no
$enable_y=yes
After I poked around in autoconf sources, I figured out this has to do with the m4_divert_once call in the implementation of AC_ARG_ENABLE:
# AC_ARG_ENABLE(FEATURE, HELP-STRING, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
# ------------------------------------------------------------------------
AC_DEFUN([AC_ARG_ENABLE],
[AC_PROVIDE_IFELSE([AC_PRESERVE_HELP_ORDER],
[],
[m4_divert_once([HELP_ENABLE], [[
Optional Features:
--disable-option-checking ignore unrecognized --enable/--with options
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]]])])dnl
m4_divert_once([HELP_ENABLE], [$2])dnl
_AC_ENABLE_IF([enable], [$1], [$3], [$4])dnl
])# AC_ARG_ENABLE
# m4_divert_once(DIVERSION-NAME, CONTENT)
# ---------------------------------------
# Output CONTENT into DIVERSION-NAME once, if not already there.
# An end of line is appended for free to CONTENT.
m4_define([m4_divert_once],
[m4_expand_once([m4_divert_text([$1], [$2])])])
I'm guessing that the HELP-STRING argument is remembered in it's unexpanded form, so it is added just once for all components. Manually expanding the AC_HELP_STRING does what I want:
AC_DEFUN([COMPONENTS],
[
m4_foreach_w([comp], [$1], [
AS_ECHO(["Processing component 'comp' with default enable=$2"])
AC_ARG_ENABLE([comp],
m4_expand([AS_HELP_STRING([--enable-comp], enable component comp)]),
,
[enable_[]AS_TR_SH([comp])=$2]
)
])
])
COMPONENTS([a b c x y], [yes])
I couldn't find a way to properly quote components so that it appears as a string, after being used as the loop variable in m4_foreach_w, so I just renamed it to spare me the trouble.

Interleave blocks, or make object out of two blocks (field names and values)

Instead of creating objects by writing:
obj: object [
name: "Fork"
id: 1020
]
I'd like to write something like...
obj: something-or-another [name id] ["Fork" 1020]
...and get the same result. An ideal solution would also permit:
obj: something-or-another [name: id:] ["Fork" 1020]
Easy enough to write a something-or-another, but does this fit something already "in the box"?
I don't believe there's a baked-in way to do this. Not difficult though:
func [words values][
set words: context append map-each word words [to set-word! word] none values
words
]
I suppose I could break this down a little:
func [
"Creates an Object From a Block of Words, Assigns Values"
words [block!] "Words used to create object"
values "Value(s) to assign"
][
words: map-each word words [to set-word! word] ; The requisite set-words
append words none ; Initial value for all words
words: context words ; Create our object
set words values ; Assigns our value(s) to the object
words ; returns the object
]
You might employ a different method to interleave blocks, such as:
func [words [block!] values [block!]][
collect [
repeat index max length? words length? values [
keep words/:index
keep values/:index
]
]
]
Here's something that requires at least Rebol 3:
func [
"Create an object based on some words and values."
words [any-word! block!] "Word or block of words"
values [any-type!] "Value or block of values"
/local object
][
object: make object! either block? words [length? words] [1]
set bind/copy/new :words object :values
object
]
If you want to also allow setting unset values, try this:
func [
"Create an object based on some words and values."
words [any-word! block!] "Word or block of words"
values [any-type!] "Value or block of values"
/any "Allows setting words to any value, including unset"
/local object
][
object: make object! either block? words [length? words] [1]
apply :set [bind/copy/new :words object :values any]
object
]
Both of these create objects with self, so if you want to create an object without self you have to do some fancier tricks. See the selfless proposal for details.
I wrote a similar function (Rebol2) just a few days ago:
build-object: func [
"Builds an object from a block"
names [block!] "Field names"
/values val [block!] "Initial values"
/local o name value
] [
o: copy []
names: compose names
o: either values [
parse names [
some [
set name [word! | set-word!]
(append o to-set-word name)
| skip
]
]
set/pad reflect o: context append o none 'words val
o
] [
if any [
parse names [
some [
set name [word! | set-word!]
(append o reduce [to-set-word name none])
]
]
parse names [
(clear o) some [
set name [word! | set-word!] set value any-type!
(append o reduce [to-set-word name :value])
]
]
] [context o]
]
o
]
To build your object you could write any of: (create a function as f: does ["x"])
build-object [name "Fork" id 1020]
build-object [name: "Fork" id: 1020]
build-object/values [name id] ["Fork" 1020]
build-object/values [name: id:] ["Fork" 1020]
build-object [name f]
build-object [name (f)] ;block is composed
build-object [name 5 id f]
build-object [name 5 id 'f]
You can also make objects with fields set to none if you leave the values out, e.g. with
build-object [name id]

Resources