How to validate a path given in an inputdialog? - validation

I'm trying to validate a path given in an inputdialog.
"a = path to file p.e. d:\mydoc.txt (but can be every file)
let a = inputdialog(docinput)
while 1
try
read (a)
catch /E484:/
echo "The file doesn't exist"
let a = inputdialog(docinput,a,"return")
if a == "return"
return
endif
endtry
endwhile
I want to check if the filename exists using the read command.
But it seems that read cannot read a variable.
read has to be something like this:
read d:\mydoc.txt
1) How can I read a variable?
If read gives an error message (E484 (cannot read the file)), the script has to return to the inputdialog.
I tried to do this with a try/endtry within a while/endwhile loop but I haven't found out how to break out of the loop.
2) How can I return the script to the inputdialog if the file doesn't exist?

You must use :execute to :read the filename contained in variable a:
execute "read " . a
:read is the wrong tool for the job, use filereadable() (or filewriteable(), depending on what you want to do with that file) instead:
if filereadable(expand(a))
" do something
else
" do something else
endif
I can't understand your second question.

Related

IDL compilation doesnt return failure status

I dont have much experience with IDL but i need to fix a bug where in the compilation failure status needs to be returned to the calling script.
cat << ENDCAT > something.pro
PRINT, "Start"
PRINT, "Compiling functions needing early compile"
#do_early_func
PRINT, "Compiling remaining functions"
#do_other_func
PRINT, "Running: resolve_all"
resolve_all
EXIT
ENDCAT
setenv IDL_STARTUP something.pro
$IDL_DIR/bin/idl
The above content exists in a script called make_program which is called by another script called the build_script
The problem i am facing is that even if 'resolve_all' results in a compilation failure, the make_program always returns a true to the build_script making it think the compilation succeeded when it actually didnt. How can i return the failure status back to the calling script?
The EXIT routine has a STATUS keyword that can return the exit status of the script. So something like:
exit, status=status_code
To determine if RESOLVE_ALL completed correctly, you may need to do a CATCH block. The easiest way is probably to wrap RESOLVE_ALL in your own routine that has an ERROR keyword that returns whether the RESOLVE_ALL succeeded.
I'm not sure where I picked this up but you'll need two routines:
function validate_syntax_helper, routineName
compile_opt strictarr, hidden
catch, error
if (error ne 0) then return, 0
resolve_routine, routineName, /either, /compile_full_file
return, 1
end
and
function validate_syntax, routineName
compile_opt strictarr, hidden
oldquiet = !quiet
!quiet = 1
catch, error
if (error ne 0) then return, 0
; Get current directory
cd, current=pwd
o = obj_new('IDL_IDLBridge')
o->execute, '#' + pref_get('IDL_STARTUP')
; Change to current directory
o->execute, 'cd, ''' + pwd + ''''
; Validate syntax
cmd = 'result = validate_syntax_helper(''' + routineName + ''')'
o->execute, cmd
result = o->getVar('result')
obj_destroy, o
!quiet = oldquiet
return, result
end
You then call validate_syntax, which returns 1 when it can compile and 0 when it can't. I don't think this can be used from the IDL virtual machine since it uses execute, but maybe that doesn't matter to you. You'll have to manually run this on all your routines to be compiled instead of running resolve_all.

if statement not separating content

See this snippet of code:
exclude = ["BURSAR", "SHOP"]
for name in exclude:
if name in machineName: # machineName is defined further up in the script.
inputText.insert("end", machineName + " has been excluded.\n")
else:
command = subprocess.Popen( commands here...)
It's job is to exclude any machine which includes certain words within it's name.
Currently, if I pass two machines to the script, one of which is called 'BURSAR3' (for example), it will register the fact that it should be excluded, and runs the inputText to show that fact. Unfortunately it also continues to pass the name to the command below, when it shouldn't. I can even replace the 'else:' with 'if name not in exclude:' and it will still fail in the same way!
What have I done wrong here? It looks like it should be so simple...
Thanks,
Chris.
p.s. apologies if the title is rubbish - I couldn't think how to define it better...
Use the optional else after a for:
exclude = ["BURSAR", "SHOP"]
for name in exclude:
if name in machineName: # machineName is defined further up in the script.
inputText.insert("end", machineName + " has been excluded.\n")
break
else:
command = subprocess.Popen( commands here...)
The else is executed ONLY if the for loop completed naturally, without encountering the break. Thus, if none of the blacklisted words appear in the machine name, the else block is executed.
Of course, there's an easier way to do this:
exclude = ["BURSAR", "SHOP"]
if any((name in machineName for name in exclude)): # machineName is defined further up in the script.
inputText.insert("end", machineName + " has been excluded.\n")
else:
command = subprocess.Popen( commands here...)

How do I create a file using sudo and write into it?

I created a bash script file:
#!/bin/bash
default_card=`head -1 /proc/asound/modules`
echo $default_card
if [ ! -e /etc/modprobe.d/sound.blacklist.conf ] ; then
echo "Default sound card(snd_hda_intel) is not added in black list"
/usr/bin/expect <<delim
exp_internal 0
set timeout 20
spawn sudo sh -c "echo 'blacklist snd_hda_intel' > /etc/modprobe.d/sound.blacklist.conf"
expect "password for ubuntu:"
send "1234\n"
expect eof
delim
else
echo "Default sound cardis already added in black list";
fi
I am creating a black list file in "/etc/modprobe.d". Creating or deleting any file from "/etc" requires sudo access.
I want to implement the same functionality in Ruby using a Rake task. I created the task as:
desc "Check/creates soundcard blacklist"
task :create_blacklist do
begin
if !File.exists?("/etc/modprobe.d/sound.blacklist.conf")
# code for creating new file and write into it
......
......
else
puts "Sound-card blacklist file is present at /etc/modprobe.d/sound.blacklist.conf"
end
rescue Exception => e
puts "problem creating file #{e.message}"
end
end
I don't know how to create new file using sudo, and write into it.
I am using Ruby 1.9.3 (without RVM).
Look at https://stackoverflow.com/a/18366155/128421, https://stackoverflow.com/a/18398804/128421, and "communicating w/ command-line program (OR ruby expect)" for more information.
Ruby's IO class implements expect but it's not too full-featured:
=== Implementation from IO
------------------------------------------------------------------------------
IO#expect(pattern,timeout=9999999) -> Array
IO#expect(pattern,timeout=9999999) { |result| ... } -> nil
------------------------------------------------------------------------------
Reads from the IO until the given pattern matches or the timeout is over.
It returns an array with the read buffer, followed by the matches. If a block
is given, the result is yielded to the block and returns nil.
When called without a block, it waits until the input that matches the given
pattern is obtained from the IO or the time specified as the timeout passes.
An array is returned when the pattern is obtained from the IO. The first
element of the array is the entire string obtained from the IO until the
pattern matches, followed by elements indicating which the pattern which
matched to the anchor in the regular expression.
The optional timeout parameter defines, in seconds, the total time to wait for
the pattern. If the timeout expires or eof is found, nil is returned or
yielded. However, the buffer in a timeout session is kept for the next expect
call. The default timeout is 9999999 seconds.

simple rest api server to pass arguments to a shell script and execute it on shell

I simply want to have a rest api server which I can call to update a file via a URL, that's it.
Here is the file:
mytextfile:
key1 = value1
key2 = value2
On the client, a script will be run which sends a string or strings to the API server.
The API server will receive them, for example /update.script?string1="blah"&string2="fun" (pretend its url encoded)
The server should then parse these strings, and then call an exec function, or another script even on the system which does some sed command to update a file
Language or implementation doesn't matter.
Looking for fresh ideas.
All suggestions are appreciated.
I don't get it: What exactly is your problem/question?
My approach to the problem "modifying a file from inside a cgi script using url-encoded arguments" would be:
Pick a language you like and start coding, in my case with Perl.
#!/usr/bin/perl
use strict; use warnings;
Fetch all your arguments. I will use the CGI module of Perl here:
use CGI::Carp;
use CGI;
my $cgi = CGI->new;
# assuming we don't have multivalued fields:
my %arguments = $cgi->Values; # handles (almost) *all* decoding and splitting
# validate arguments
# send back CGI header to acknowledge the request
# the server will make a HTTP header from that
Now either call a special subroutine / function with them …
updateHandler(%arguments);
...;
my $filename = 'path to yer file name.txt';
sub updateHandler {
my %arguments = #_;
# open yer file, loop over yer arguments, whatever
# read in file
open my $fileIn, '<', $filename or die "Can't open file for reading";
my #lines = <$fileIn>;
close $fileIn;
# open the file for writing, completely ignoring concurrency issues:
open my $fileOut, '>', $filename or die "Can't open file for writing";
# loop over all lines, make substitutions, and print it out
foreach my $line (#lines) {
# assuming a file format with key-value pairs
# keys start at the first column
# and are seperated from values by an '=',
# surrounded by any number of whitespace characters
my ($key, $value) = split /\s*=\s*/, $line, 2;
$value = $arguments{$key} // $value;
# you might want to make sure $value ends with a newline
print $fileOut $key, " = ", $value;
}
}
Please don't use this rather insecure and suboptimal code! I just wrote this as a demonstration that this isn't really complicated.
… or contrieve a way to send your arguments to another script (although Perl is more than well suited for file manipulation tasks). Choose one of the qw{}, system or exec commands, depending on what output you need from your script, or decide to pipe your arguments to the script using the open my $fh, '|-', $command mode of open.
As for the server to run this script on: Apache looks fine to me, unless you have very special needs (your own protocol, single-threading, low security, low performance) in which case you might want to code your own server. Using the HTTP::Daemon module you might manage <50 lines for a simplicistic server.
When using Apache, I'd strongly suggest using mod_rewrite to put the /path into the PATH_INFO environment variable. When using one script to represent your whole REST API, you could use the PATH_INFO to choose one of many methods/subroutines/functions. This also eliminates the need to name the script in the URL.
For example, turn the URL
http://example.com/rest/modify/filename?key1=value1
into
/cgi-bin/rest-handler.pl/modify/filename?key1=value1
Inside the Perl script, we would then have $ENV{PATH_INFO} containing /modify/filename.
This is a bit Perl-centric, but just pick any language you are comfortable with and start coding, leveraging whatever module you can use on the way.
I would use a newer Perl framework, like Mojolicious. If I make a file (test.pl):
#!/usr/bin/env perl
use Mojolicious::Lite;
use Data::Dumper;
my $file = 'file.txt';
any '/' => sub {
my $self = shift;
my #params = $self->param;
my $data = do $file;
$data->{$_} = $self->param($_) for #params;
open my $fh, '>', $file or die "Cannot open $file";
local $Data::Dumper::Terse = 1;
print $fh Dumper $data;
$self->render( text => "File Updated\n" );
};
app->start;
Then run morbo test.pl
and visit http://localhost:3000/?hello=world (or run ./test.pl get /?hello=world)
then I get in file.txt:
{
'hello' => 'world'
}
and so on.

Saving Tab names and ConqueShells along with Vim sessions

Is there any way to get vim to save the tab names (assigned via the Tab Name script) and/or a terminal emulator (set up via the Conque Shell script) upon issuing the :mksession [fileName] command?
Observe below (zoom in), I have a working session on the left, and the same session loaded via the vim -S fileName command, on the right. The assigned tab labels revert to absolute paths, ConqueShell terminal is interpreted as a file.
After learning some basic VimScript I just gave up and used Python instead (to cite one example, you can't save global information to a session if it is a list). Here is a solution I found for saving tab names (will post a solution for ConqueShell if I find one)
Put the following in your .vimrc file and use whatever mapping you want to quickly save and load your sessions
"Tokenize it so it has the following form (without spaces)
"Label1 JJ Label2 JJ Label3 JJ Label4
"Or if you prefer use something other than 'JJ' but DO NOT
"use symbols as they could interfere with the shell command
"line
function RecordTabNames()
"Start at the first tab with no tab names assigned
let g:TabNames = ''
tabfirst
"Iterate over all the tabs and determine whether g:TabNames
"needs to be updated
for i in range(1, tabpagenr('$'))
"If tabnames.vim created the variable 't:tab_name', append it
"to g:TabNames, otherwise, append nothing, but the delimiter
if exists('t:tab_name')
let g:TabNames = g:TabNames . t:tab_name . 'JJ'
else
let g:TabNames = g:TabNames . 'JJ'
endif
"iterate to next tab
tabnext
endfor
endfunction
func! MakeFullSession()
call RecordTabNames()
mksession! ~/.vim/sessions/Session.vim
"Call the Pythin script, passing to it as an argument, all the
"tab names. Make sure to put g:TabNames in double quotes, o.w.
"a tab label with spaces will be passed as two separate arguments
execute "!mksession.py '" . g:TabNames . "'"
endfunc
func! LoadFullSession()
source ~/.vim/sessions/Session.vim
endfunc
nnoremap <leader>mks :call MakeFullSession()<CR>
nnoremap <leader>lks :call LoadFullSession()<CR>
Now create the following text file and put it somewhere in your PATH variable (echo $PATH to get it, mine is at /home/user/bin/mksession.py) and make sure to make it executable (chmod 0700 /home/user/bin/mksession.py)
#!/usr/bin/env python
"""This script attempts to fix the Session.vim file by saving the
tab names. The tab names must be passed at the command line,
delimitted by a unique string (in this case 'JJ'). Also, although
spaces are handled, symbols such as '!' can lead to problems.
Steer clear of symbols and file names with 'JJ' in them (Sorry JJ
Abrams, that's what you get for making the worst TV show in history,
you jerk)
"""
import sys
import copy
if __name__ == "__main__":
labels = sys.argv[1].split('JJ')
labels = labels[:len(labels)-1]
"""read the session file to add commands after tabedit
" "(replace 'USER' with your username)
"
f = open('/home/USER/.vim/sessions/Session.vim', 'r')
text = f.read()
f.close()
"""If the text file does not contain the word "tabedit" that means there
" "are no tabs. Therefore, do not continue
"""
if text.find('tabedit') >=0:
text = text.split('\n')
"""Must start at index 1 as the first "tab" is technically not a tab
" "until the second tab is added
"""
labelIndex = 1
newText = ''
for i, line in enumerate(text):
newText +=line + '\n'
"""Remember that vim is not very smart with tabs. It does not understand
" "the concept of a single tab. Therefore, the first "tab" is opened
" "as a buffer. In other words, first look for the keyword 'edit', then
" "subsequently look for 'tabedit'. However, when being sourced, the
" "first tab opened is still a buffer, therefore, at the end we will
" "have to return and take care of the first "tab"
"""
if line.startswith('tabedit'):
"""If the labelIndex is empty that means it was never set,
" "therefore, do nothing
"""
if labels[labelIndex] != '':
newText += 'TName "%s"\n'%(labels[labelIndex])
labelIndex += 1
"""Now that the tabbed windowing environment has been established,
" "we can return to the first "tab" and set its name. This serves
" "the double purpose of selecting the first tab (if it has not
" "already been selected)
"""
newText += "tabfirst\n"
newText += 'TName "%s"\n'%(labels[0])
#(replace 'USER' with your username)
f = open('/home/USER/.vim/sessions/Session.vim', 'w')
f.write(newText)
f.close()

Resources