With Qt, how to check if stdin is empty? - qt

I have a Qt program that processes stdin data like this:
QTextStream qtin(stdin);
QString stdindata = qtin.readAll();
QByteArray ba;
ba = stdindata.toUtf8();
QJsonDocument exJSONDoc(QJsonDocument::fromJson(ba));
QJsonObject extRoot;
extRoot = exJSONDoc.object();
QStringList keys;
keys = extRoot.keys();
for (int n=0; n <= keys.count()-1; n++)
{
qDebug() << extRoot.value(keys[n]).toString();
}
It works when I call my program like this:
myprogram < ./data.json
But if I call it without any "<" it hangs in qtin.readAll().
How can I check with Qt if the stdin is empty?

(I am assuming a Linux -or at least POSIX- operating system)
QTextStream qtin(stdin);
QString stdindata = qtin.readAll();
This would read stdin till end-of-file is reached. So works with a redirected input like
myprogram < ./data.json
But if I call it without any "<" it hangs ...
But then (that is, if you run myprogram alone) stdin is not empty. It is the same as your shell's stdin. and your program, being the foreground job, is waiting for input on the terminal you are typing (see also tty(4)). Try (in that case) typing some input on the terminal (which you could end with Ctrl D to make an end-of-file condition). Read about job control and the tty demystified and see also termios(3).
Perhaps you could detect that situation with e.g. isatty(3) on STDIN_FILENO. But that won't detect a pipe(7) like
tail -55 somefile | myprogram
You need to define what an empty stdin is for you. I have no idea what that means to you, and I would instead think of myprogram < /dev/null (see null(4)) as the way to get an empty stdin.
Perhaps you should design myprogram so that some program
option (perhaps --ignore-stdin) is avoiding any read from stdin.

Problem here is readAll. See documentation:
Reads the entire content of the stream, and returns it as a QString.
Avoid this function when working on large files, as it will consume a
significant amount of memory.
So it reads stdin until it encounters end of file and since stdin is associated with console you have to signal end of file. Usually it is Ctrl-D and press enter.
It is more probable you what to read stdin line by line.
To alow user text editing console transfers data to standard input of the application only line by line. This was designed like this ages ago when computer had only a printer as user interface (no screen).
Now question is how to read JSon form stdin console connected with console without end of file information?
I would use some SAX parser, but this would be to complicated for you.
So is there another way to detect end of JSon?
You can try this approach (this is basic idea, not final solution, so it has couple shortcomings):
QFile file(stdin);
QByteArray data = file.peak(largeNumber);
QJsonParseError error;
QJSonDocument doc = QJSonDocument::fromJson(data, &error);
while (!doc.isValid() && JSonNotTerminatedError(error.error))
{
// TODO: wait for new data - it would be best to use readyRead signal
doc = QJSonDocument::fromJson(data, &error);
}
Where JSonNotTerminatedError returns true for respective QJsonParseError::ParseError values (see linked documentation) which are related with unterminated JSon data.
Now I see QFile doesn't have required constructor, but main concept should be clear. Read data from stdin and check if it is a valid JSon document.

Related

read() does not read data from pty despite they are

My program is supposed to emulate external device that is usually connected via COM port (/dev/ttyUSB0). The program opens a pty and waits for commands. Here is the code:
HostPty::HostPty(const string & HostPty_name)
{
char name[100] = {0};
int res = openpty(&_master, &_slave, name, NULL, NULL);
printf("Name: %s\n", name);
}
string HostPty::nextString()
{
static const int BUF_SIZE = 4096;
char buf[BUF_SIZE];
size_t idx = 0;
while(true)
{
// Read symbols one by one until new line is found
size_t received_size = read(_master, buf + idx, 1);
printf("Received a symbol: %02x\n", buf[idx]);
// Stopping at new line
if(buf[idx] == '\n')
break;
idx++;
}
return string(buf, idx);
}
To test this code I am using miniterm.py terminal emulator connecting to /dev/pty/6 (or whatever is created with openpty) and send text commands over there.
When I type commands manually everything works fine - I receive chars one by one as expected. But when I paste a piece of multiline text this code receives only first byte until I put a new line symbol (even though there are multiple newline symbols in the text I paste).
Any ideas how to fix that?
Any ideas how to fix that?
I don't know which kind of Unix you have. I just tried to reproduce your problem under Linux; but pasting lines work fine on my computer so I cannot reproduce the problem.
If your Unix variant has a system call tracer (Linux: strace, SunOS/Solars: truss, FreeBSD: strace, MacOS: dtruss (?)), I'd trace the system calls:
strace -f -o file_myprog.out ./my_program
miniterm /dev/pty/6
(Note the -f which means that the system calls of sub-processes created by fork() are also debugged. This is necessary because Python will create such sub-processes.)
Now reproduce the situation when the program does not behave correctly and kill my_program using pkill -KILL my_program. (Send the -KILL signal to ensure that my_program is killed immediately.)
Do that again - this time debugging miniterm and killing miniterm in the "wrong situation":
./my_program
strace -f -o file_miniterm.out miniterm /dev/pty/6
At the end of the two output files (file_myprog.out and file_miniterm.out) you can see the last "actions" the two programs were doing before you killed them. There are various scenarios possible:
miniterm was sending the data to /dev/pty/6 but your program did not receive any data. In this case there is a problem with the virtual console itself.
miniterm did not send the data to /dev/pty/6 for some reason. In this case you have a problem with miniterm.
miniterm did not even receive the data pasted using read()...

Qt qaxwidget setcontrol() from file name in order to "xxx.doc" show in widget,but then the winword.exe process can't quit

I've tried two ways to load a Word document into Qt qaxwidget, but neither successfully quits the winword.exe process.
My first attempt
ui->axWidget->setControl("D:/1.doc");
QAxObject *app = ui->axWidget->querySubObject("Application");
app->dynamicCall("Quit()");
Sometimes the following will work, but not reliably:
ui->axWidget->("Word.Application");
setProperty("DisplayAlerts", false);
setProperty("Visible", false);
ui->axWidget->setControl("D:/1.doc");//then call this line of code
QAxObject *app = ui->axWidget->querySubObject("Application");
ui->axWidget->dynamicCall("Close(bool)", false);
ui->axWidget->clear();
app->dynamicCall("Quit()");
What should I do to properly clos thee "winword.exe" process?
My enviroment is qt4.8.0+vs2008.
The first solution should be correct,but there are some other thing that limit me from closing the process.
The second solution is completely an error,When I call ui->axWidget->setControl("D:/1.doc");,"Word.Application" is out of control.
So,we wanna load a Word document into Qt qaxwidget firmly,my solution is
QProcess p;
QString c = "taskkill /im winword.exe /f";
p.execute(c);
p.close();

AutoIt Scripting for an External CLI Program - eac3to.exe

I am attempting to design a front end GUI for a CLI program by the name of eac3to.exe. The problem as I see it is that this program sends all of it's output to a cmd window. This is giving me no end of trouble because I need to get a lot of this output into a GUI window. This sounds easy enough, but I am begining to wonder whether I have found one of AutoIt's limitations?
I can use the Run() function with a windows internal command such as Dir and then get the output into a variable with the AutoIt StdoutRead() function, but I just can't get the output from an external program such as eac3to.exe - it just doesn't seem to work whatever I do! Just for testing purposesI I don't even need to get the output to a a GUI window: just printing it with ConsoleWrite() is good enough as this proves that I was able to read it into a variable. So at this stage that's all I need to do - get the text (usually about 10 lines) that has been output to a cmd window by my external CLI program into a variable. Once I can do this the rest will be a lot easier. This is what I have been trying, but it never works:
Global $iPID = Run("C:\VIDEO_EDITING\eac3to\eac3to.exe","", #SW_SHOW)
Global $ScreenOutput = StdoutRead($iPID)
ConsoleWrite($ScreenOutput & #CRLF)
After running this script all I get from the consolWrite() is a blank line - not the text data that was output as a result of running eac3to.exe (running eac3to without any arguments just lists a screen of help text relating to all the commandline options), and that's what I am trying to get into a variable so that I can put it to use later in the program.
Before I suggest a solution let me just tell you that Autoit has one
of the best help files out there. Use it.
You are missing $STDOUT_CHILD = Provide a handle to the child's STDOUT stream.
Also, you can't just do RUN and immediately call stdoutRead. At what point did you give the app some time to do anything and actually print something back to the console?
You need to either use ProcessWaitClose and read the stream then or, you should read the stream in a loop. Simplest check would be to set a sleep between RUN and READ and see what happens.
#include <AutoItConstants.au3>
Global $iPID = Run("C:\VIDEO_EDITING\eac3to\eac3to.exe","", #SW_SHOW, $STDOUT_CHILD)
; Wait until the process has closed using the PID returned by Run.
ProcessWaitClose($iPID)
; Read the Stdout stream of the PID returned by Run. This can also be done in a while loop. Look at the example for StderrRead.
; If the proccess doesnt end when finished you need to put this inside of a loop.
Local $ScreenOutput = StdoutRead($iPID)
ConsoleWrite($ScreenOutput & #CRLF)

How do I convert my 5GB 1 liner file to lines based on pattern?

I have a 5GB 1 liner file with JSON data and each line starts from this pattern "{"created". I need to be able to use Unix commands on my Mac to convert this monster of a 1 liner into as many lines as it deserves. Any commands?
ASCII English text, with very long lines, with no line terminators
If you have enough memory you can open the file once with the TextWrangler application (the free BBEdit cousin) and use regular search/replace on the whole file. Use \r in replace to add a return. Will be very slow at opening the file, may even hang if low on memory, but in the end it may probably work. No scripting, no commands,.. etc.. I did this with big SQL files and sometimes it did the job.
You have to replace your line-start string with the same string with \n or \r or \r\n in front of it.
Unclear how it can be a “one liner” file but then each line starts with "{"created", but perhaps python -mjson.tool can help you get started:
cat your_source_file.json | python -mjson.tool > nicely_formatted_file.json
Piping raw JSON through ``python -mjson.tool` will cleanly format the JSON to be more human readable. More info here.
OS X ships with both flex and bison, you can use those to write a parser for your data.
You can use PHP as a shell command (if PHP is installed), just save a text file with name "myscript" and appropriate code (I cannot test code now, but the idea is as follows)
UNTESTED CODE
#!/usr/bin/php
<?php
$REPLACE_STRING='{"created'; // anything you like
// open input file with fopen() in read mode
$inFp=fopen('big_in_file.txt', "r");
// open output file with fopen() in write mode
$outFp=fopen('big_out_file.txt', "w+");
// while not end of file
while (!feof($inFp)) {
// read file chunks here with fread() in variable $chunk
$chunk = fread($inFp, 8192);
// do a $chunk=str_replace($REPLACE_STRING,"\r".$REPLACE_STRING; // to add returns
// (or use \r\n for windows end of lines)
$chunk=str_replace($REPLACE_STRING,"\r".$REPLACE_STRING,$chunk);
// problem: if chunk contains half the string at the end
// easily solved if $REPLACE_STRING is a one char like '{'
// otherwise test for fist char { in the end of $chunk
// remove final part and save it in a var for nest iteration
// write $chunk to output file
fwrite($outFp, $chunk);
// End while
}
?>
After you save it you must make it executable whith sudo chmod a+x ./myscript
and then launch it as ./myscript in terminal
After this, the myscript file is a full unix command

How to creat printf with slightly different name

I am using ATmega128 and I need two serial ports for communication. I have been using printf from "stdio.h" header file to send data through USART 0. I also need to send data through USART 1 to lcd and I am curious about using formatted input function. I have been thinking that connecting same printf function to USART 1 and USART 0 makes the compiler confused so I haven't tried it.
Can anyone suggest how to make another printf say "Lprintf" to send data through USART 1 ??
What you want to do here is to use fprintf(). See the documentation on avr-libc for the function. Essentially, you want to have a fputc() function for UART1 and one for UART0. Then, based on that, you can create two FILE buffers. Once you do so, you are free to use fprintf() on each. Optionally, you can point stdout to one of these buffers, as to be able to use printf().
FILE uart1_out = FDEV_SETUP_STREAM(uart1_putc, 0, _FDEV_SETUP_WRITE);
FILE uart0_out = FDEV_SETUP_STREAM(uart0_putc, 0, _FDEV_SETUP_WRITE);
fprintf(&uart1_out, "printing to UART1");
fprintf(&uart0_out, "printing %d to UART0", 0);
stdout = &uart1_out;
stderr = &uart0_out;
printf("This string will be printed thru UART1");
fprintf(stderr, "This string will be printed thru UART0");
You just need to provide the implementation for int uart1_putc(int, FILE*) and int uart0_putc(int, FILE*) to manipulate data as you wish.
Hope this helps.
Cheers.
Depending on how you've linked it, there are two alternatives that are possibly simpler:
Use sprintf() to write your formatted text to a string, and then use your own putchar() or putstring() to send it to the desired USART.
If you're using the FILE struct to link your USARTs to the stdio functions (likely), you can use fprintf() to direct the results to a particular stream.

Resources