TCL C API Create and Register new Channel - c++

I use Tcl 8.6(windows) and i can't register and use new channels
std::ofstream file("1.txt");
Tcl_Channel kanal = Tcl_CreateChannel(Type, "myChann", file, TCL_WRITABLE);
Tcl_RegisterChannel(interp, kanal);
file.close();
and the Type is
Tcl_ChannelType* Type = new Tcl_ChannelType();
Type->closeProc = closeProc;
Type->inputProc = inputProc;
Type->outputProc = outputProc;
Type->typeName = "My own chann";
Type->version = TCL_CHANNEL_VERSION_2;
functions are simply, they have only std::cout
i run interpreter with script
"chan puts myChan whatever"
and nothing happend, no errors from interpreter, no output(console, file).
i dont know how to bite this,
this is first goal, create new chanel and use it,
the second is to replace TCL_STDOUT with my own channel(it can be std::ofstream),
so that when i run interpreter with
"puts WhatEver"
that string go to the std::ofstream

Probably you did not flush the output.
This can be done with
flush myChan
You can also configure your channel to flush at the end of line or whenever anything is written to it:
chan configure myChan -buffering line
(or none). stdout is by default configured with -buffering line

Related

Rsyslog, omprog, and python

I have an issue with Rsyslog's 'omprog' module when trying to get it to interact with my python (2.7) code. Rsyslog is supposed to send desired messages to python's stdin, yet it does not receive anything. I wonder if anyone else has had better success with this output module?
Rsyslog.conf
module(load="omprog")
template(name="sshmsg" type="string" string="%msg%")
if ($programname == "myprogram") then {
action(type="omprog"
binary="/usr/sshtrack.py"
template="sshmsg")
}
If I replace the binary with a test shell script containing a line below, it works
test.sh
!#/bin/sh
cat /dev/stdin >> /var/log/ssh2.log
I also tried reading stdin in the shell script into a variable using
var="$(</dev/stdin)"
and
var="$(cat /dev/stdin)"
Neither of the above resulted var containing anything
Finally, when trying to read stdin from python script, I get nothing. Sometimes, it says resource unavailable (errno 11) error message.
sshtrack.py
#!/usr/bin/python
import sys
f = open("/var/log/ssh2.log", "a", 0)
while True:
f.write("Starting\n")
for line in sys.stdin:
f.flush()
msg = line.strip()
if not msg:
break
f.write(msg)
f.write("\n")
f.close()
The issue seems similar to can not read correctly from STDIN except adding a non-block flag did nothing.
I notice that your template sshmsg doesn't end with a newline. Try changing it to string="%msg%\n". Though it won't matter to rsyslog, Python will not be able to give you the data until it sees a newline.
Then it should work, but you probably not see any output from your python as it is buffered. Try adding an f.flush() after the last write in the loop, or opening the file unbuffered.
omprog will keep the pipe open, sending multiple lines until your program exits.
Note, not all shells might understand $() syntax.
In case of your shell script you can use read to read into a variable.
#!/bin/bash
# This will read until \n
read log
echo $log
The python source code (tested with python 3.8.2) can be adjusted to:
#!/usr/bin/env python3
import sys
# Changed from unbuffered to buffered as unbuffered is only possible in binary mode Ref (1):
f = open("/var/log/ssh2.log", "a", 1)
while True:
f.write("Starting\n")
for line in sys.stdin:
f.flush()
msg = line.strip()
if not msg:
break
f.write(msg)
f.write("\n")
f.close()
In case you want to have the output of you executed script (debugging) you can adjust the settings in Rsyslog.conf with the output option
module(load="omprog")
template(name="sshmsg" type="string" string="%msg%")
if ($programname == "myprogram") then {
action(type="omprog"
binary="/usr/sshtrack.py"
output="/var/log/sshtrack.log"
template="sshmsg")
}
Ref (1): https://stackoverflow.com/a/45263101/13108341

Py (os.path): is there a max. size for a string before an automated breakline / return?

I hope I am able to describe my problem well, sorry in advance if it's complicated.
Question:
Does Python (or the os.path calls) automatically insert a return after an amount of characters?
Background:
I try to extract acoustic features from .wav files with the tool openSMILE.
For this purpose I pass the strings of the path (inputfile and outputfile)
via subprocess.
The SMILExtract call takes 3 arguments (-C for config; -I for inputfile -O for output file). I prepare these 3 Arguments with string operations and save the arguments in a list which gets passed to the subprocess call.
def extractFeatures(self,inputFile):
self.openSMILEsettings.append("-I " + inputFile)
outputFile = os.path.dirname(inputFile) + "/featuresOf_" +os.path.basename(inputFile)[0:-3] + "arff"
self.openSMILEsettings.append("-O " + outputFile)
print self.openSMILEsettings[2]
print ' '.join(self.openSMILEsettings)
# print subprocess.check_output(['SMILExtract'] + self.openSMILEsettings)
extractFeatures("/media/USERNAME/MountPOINT/Dir1/Dir2/Dir3/02003_SomeSesssionNumber1_and2_2323123/audioFile.wav")
In the console the output of the print command (print ' '.join(...)) looks alright (example below)
-C OSconfig/IS12_speaker_trait.conf -I /media/USERNAME/MountPOINT/Dir1/Dir2/Dir3/02003_SomeSesssionNumber1_and2_2323123/audioFile.wav -O /media/USERNAME/MountPOINT/Dir1/Dir2/Dir3/02003_SomeSesssionNumber1_and2_2323123/featuresOf_audioFile.arff
However when I try to run the code with the subprocess call I get an exception. For debugging purposes I copied the output of the print to a text Editor and it appears that a Return gets entered, it looks like this
-C OSconfig/IS12_speaker_trait.conf -I /media/USERNAME/MountPOINT/Dir1/Dir2/Dir3/02003_SomeSesssionNumber1_and2_2323123/audioFile.wav -O /media/USERNAME/MountPOINT/Dir1/Dir2/Dir3/02003_SomeSesssionNumber1_and2_2323123/featur
esOf_audioFile.arff
This is word wrap, and is caused by your text editor. Essentially, there is no newline character, but your editor cannot show the text on a single line because it's too long. As a result, it's pushing the text to a new line.
You can disable this in gedit by going to View->Preferences->Uncheck "Enable Text Wrapping".
Thank you Dyno. That explains why there was a return in the texteditor.
I meanwhile found a solution for the exectuion of the SMILExtract call.
I changed subprocess call to os.system and used a template like explained elsewhere
The new call looks like this:
def extractFeatures(self,inputFile):
self.openSMILEsettings.append("-I " + inputFile)
outputFile = os.path.dirname(inputFile) + "/featuresOf_" +os.path.basename(inputFile)[0:-3] + "arff"
self.openSMILEsettings.append("-O " + outputFile)
cmd_template = 'SMILExtract {config_path} {wav_path} {arff_path}'
os.system(cmd_template.format(
config_path=self.openSMILEsettings[0],
wav_path=self.openSMILEsettings[1],
arff_path=self.openSMILEsettings[2],
))
This now runs smoothly. Is there any downside to using os.system insted of subprocess?

Formatting text file in Python

I want to format an existing text file, the contents of text file are:
Aurangabad
Adilabad
Beed
I want to format it like:
Aurangabad|Aurangabad,
Adilabad|Adilabad,
Beed|Beed,
I am not so good in Python file handling.
the code to do so:
with open('file_name.txt','r') as file:
list_of_lines = file.readlines()
new_lines_list = []
for line in list_of_lines:
line = line.replace('\n','') #because each line end with this and we don't need it now (\n is the newline chr)
new_lines_list.append('{0}|{0}\n'.format(line)) #the same as - new_lines_list.append(line+'|'+line+'\n')
with open('file_name.txt','w') as file:
string_to_write = ''.join(new_lines_list)
file.write(string_to_write)
if you don't understand the with statement: it is basically to open the file and at the end it will close itself (and even if some exception occur it will still close (I explain bad if you don't understand go here)

Pass integer input argument for Popen.communicate()

I am pretty new to python and I am stuck with something now. I am using python 2.7.
I am trying to automate a command in shell for which I wrote a python script. I have to input an integer value to the shell for which I am using Popen.communicate(input='2'). Though input is passed, it is passed as a string and the subprocess needs it as a numeric value. When I try to pass it as a numberic value like Popen.communicate(input=2) it throws the following error :
TypeError: 'int' object has no attribute '__getitem__'
So is there any way to send the input as a numeric value ??
Here is the code I use :
import sys
from subprocess import Popen, PIPE, STDOUT
cmd = ["sudo", "./sbt", "project java-examples", "run"]
proc = Popen(cmd, bufsize=4096, shell=False, stdout=PIPE, stdin=PIPE, stderr=STDOUT)
string = proc.communicate(input='2')
print string[0]
proc.stdin.close()
Edit :
Sorry that I didn't mentioned this at the first place.
My java application has multiple main classes hence the compiler ask which class to be executed, and I need to enter the same number every time,which is why I am trying to automate it. When I am passing a string value it throws numberformatexception.
Finally I found the solution for this.
Well the solution to this was pretty simple
when I changed
string = proc.communicate(input='2')
to
string = proc.communicate(input='2\n')
it worked fine.
The ./sbt process you are calling needs to be able to read a string and convert it into a integer. It is not possible to send native Python types to a child process with only Popen.
Another potential solution would be to serialize the data into JSON, YAML, XML, python pickle format, etc - choose your standard. However as you are passing a single integer this would seem very much overkill.
Pipes are byte streams in Unix. There is no numeric input -- there is only "string" input (there are no numbers or anything else -- there are only bytes).
If your child java process expects a number as its ascii representation then .communicate(input='2') is correct already if the subprocess reads from stdin (System.in). If the java process reads from the console directly (System.console().readLine()) then stdin=PIPE won't work (you might need to provide a pty in this case e.g., using pexpect).
For example, to read an integer from stdin and print it back in Java:
import java.util.Scanner;
public class ReadInteger
{
public static void main(String args[])
{
Scanner in = new Scanner(System.in);
int i = in.nextInt();
System.out.println("got " + i);
}
}
To pass an integer from Python process to the Java process via a pipe:
#!/usr/bin/env python2
from subprocess import Popen, PIPE
p = Popen(['java', '-ea', 'ReadInteger'], stdin=PIPE, stdout=PIPE)
output = p.communicate(input='2')[0]
print 'from java {' + output.strip() + '}'
It works (the output is from java {got 2}).
It stops working if the child process reads from the console instead:
public class ReadIntegerConsole
{
public static void main(String args[])
{
int i = Integer.parseInt(System.console().readLine());
System.out.println("got " + i);
}
}
The same python script leads to NullPointerException (and the output is from java {}) because System.console() is null here (stdin is redirected). It works if we provide a pseudo-tty:
#!/usr/bin/env python2
import pexpect # $ pip install pexpect
child = pexpect.spawn('java -ea ReadIntegerConsole')
child.setecho(False)
child.sendline('2')
child.expect(pexpect.EOF)
child.close()
print "from java {" + child.before.strip() + "}"
It works (the output is from java {got 2}).

Reading from COM port into a text file in python

I have a list of commands saved in text file ('command.log') which I want to run against a unit connected to 'COM5' and save the response for each command in a text file ('output.log'). The script gets stuck on the first command and I could get it to run the remaining commands. Any help will be appreciated.
import serial
def cu():
ser = serial.Serial(
port='COM5',
timeout=None,
baudrate=115200,
parity='N',
stopbits=1,
bytesize=8
)
ser.flushInput()
ser.flushOutput()
## ser.write('/sl/app_config/status \r \n') #sample command
fw = open('output.log','w')
with open('data\command.log') as f:
for line in f:
ser.write(line + '\r\n')
out = ''
while out != '/>':
out += ser.readline()
fw.write(out)
print(out)
fw.close()
ser.close()
print "Finished ... "
cu()
The bytes problem
First of all, you're misusing the serial.readline function: it returns a bytes object, and you act like it was a str object, by doing out += ser.readline(): a TypeError will be raised. Instead, you must write out += str(ser.readline(), 'utf-8'), which first converts the bytes into a str.
How to check when the transmission is ended ?
Now, the problem lays in the out != '/>' condition: I think you want to test if the message sent by the device is finished, and this message ends with '/<'. But, in the while loop, you do out += [...], so in the end of the message, out is like '<here the message>/>', which is totally different from '/>'. However, you're lucky: there is the str.endswith function! So, you must replace while out != '\>' by while not out.endswith('\>'.
WWhatWhat'sWhat's theWhat's the f*** ?
Also, in your loop, you write the whole message, if it's not already ended, in each turn. This will give you, in output.log, something like <<me<mess<messag<messag<message>/>. Instead, I think you want to print only the received characters. This can be achieved using a temporary variable.
Another issue
And, you're using the serial.readline function: accordingly to the docstrings,
The line terminator is always b'\n'
It's not compatible with you're code: you want your out to finish with "\>", instead, you must use only serial.read, which returns all the received characters.
Haaaa... the end ! \o/
Finally, your while loop will look as follows:
# Check if the message is already finished
while not out.endswith('/>'):
# Save the last received characters
# A `bytes` object is encoded in 'utf-8'
received_chars = str(ser.read(), 'utf-8')
# Add them to `out`
out += received_chars
# Log them
fw.write(received_chars)
# Print them, without ending with a new line, more "user-friendly"
print(received_chars, end='')
# Finally, print a new line for clarity
print()