Strange output from C pipes

I have a brand new C++ class to open processes using pipes, fork and exec. The only issue I have is when I write the lines readed from the 'stdout' pipe using fgets. Executing the command ls -lohAFGH -D %Y.%m.%d %H:%M /usr/local I get

Code:
total 236
         drwxr-xr-x    5 root  wheel  -   45K 2014.03.15 14:08 bin/
                                                                   drwxr-xr-x    2 root  wheel  -  512B 2014.03.06 18:45 env/
                                drwxr-xr-x   43 root  wheel  -  1.5K 2014.03.15 14:08 etc/
                                                                                          drwxrwxr-x   11 root  wheel  -  512B 2013.10.06 02:55 freethread/
                                                              drwxr-xr-x    5 root  wheel  -  512B 2014.01.26 19:59 freethread.local/
                                        drwxr-xr-x  287 root  wheel  -   36K 2014.03.13 20:14 include/
         drwxr-xr-x    4 root  wheel  -  2.0K 2014.03.11 14:00 info/
                                                                    drwxr-xr-x   79 root  wheel  -   81K 2014.03.13 20:14 lib/
                                 drwxr-xr-x    3 root  wheel  -  512B 2014.03.03 05:21 lib32/
drwxr-xr-x    8 root  wheel  -  512B 2014.03.03 17:23 libdata/
                                                              drwxr-xr-x   10 root  wheel  -  2.5K 2014.03.11 13:59 libexec/
                               drwxr-xr-x   49 root  wheel  -  1.0K 2014.03.07 20:59 man/
                                                                                         drwxr-xr-x   23 root  wheel  -  512B 2014.03.03 14:18 netbeans-7.4/
                                                               drwxr-xr-x    9 root  wheel  -  512B 2014.03.13 02:54 openjdk6/
                                 drwxr-xr-x    9 root  wheel  -  512B 2014.03.06 22:15 openjdk7/
   drwxr-xr-x    2 root  wheel  -  1.0K 2014.03.07 20:43 sbin/
                                                              drwxr-xr-x  154 root  wheel  -  3.0K 2014.03.15 00:45 share/
                             drwxr-xr-x    2 root  wheel  -  512B 2014.03.03 01:28 tests/
                                                                                         drwxr-xr-x    2 root  wheel  -  512B 2014.03.03 01:28 www/
                                                      drwxr-xr-x    4 root  wheel  -  512B 2014.03.03 03:48 x86_64-portbld-freebsd10.0/                                                   
                                          OUT ERROR: 9                                       
                                                      >>> Unimplemented

each line is written with

Code:
cout << s;

yes, I also have an EBADF error, the code is still a mess. It seems that the console want a '\r\n' instead of a '\n'. Anyone for an hint?
 
The code. Initially I started looking at popen/pclose, but the interface has no stderr and I need to trap it to avoid dirty screen (TUI). I'm sorry for the naming convention and the pseudo-hungarian notation I'm used. There are two classes: one base abstractact class and the derived class, I already use the base for other platforms.

Code:
class ProcessBase
{
    // Constructors and Destructors
public:
    ProcessBase ();
    virtual ~ProcessBase ();
    
    // Fields
protected:
    String                          _sCmd;
    Array<String>                   _aArgs;
    String                          _sExecDir;
    Bool                            _bRunInShell;
    Bool                            _bStarted;
    Bool                            _bRunning;
    Int                             _iExitStatus;
    
    // Methods
public:
    virtual Bool IsRunning () = 0;
    virtual Bool Start (const String & sCmd, const Array<String> & aArgs,
                        const String & sExecDir = Text ("")) = 0;
    virtual Bool Exit () = 0;
    virtual Bool Wait () = 0;
    virtual Bool In (const String & sText) const = 0;
    virtual String Out () const = 0;
    virtual String Err () const = 0;
};

The derived class has some private fields specific to FreeBSD.

Code:
    // Fields
private:
    Int                             _iPID;
    // stdin FD and FILE
    Int                             _iStdIn;
    FILE *                          _oStdIn;
    // stdout FD and FILE
    Int                             _iStdOut;
    FILE *                          _oStdOut;
    // stderr FD and FILE
    Int                             _iStdErr;
    FILE *                          _oStdErr;

There still Exit method not implemented. The relevant code is as follow

method Start
This is where the most happens.
Code:
    // Data initialization and pipes creation
    Int iStdIn[2] = { IDNull, IDNull };
    Int iStdOut[2] = { IDNull, IDNull };
    Int iStdErr[2] = { IDNull, IDNull };
    Int iPID = IDNull;
    Int iResult = ::pipe (iStdIn);
    if (iResult == 0)
    {
        iResult = ::pipe (iStdOut);
        if (iResult == 0)
            iResult = ::pipe (iStdErr);
    }
    ...
    // Forking
    iPID = ::fork ();
    if (iPID > 0)
    {
        // Parent process (this)
        // Close unnecessary pipe endpoints
        ::close (iStdIn[0]);
        ::close (iStdOut[1]);
        ::close (iStdErr[1]);
        // Set data fields
        _iPID = iPID;
        _iStdIn = iStdIn[1];
        _iStdOut = iStdOut[0];
        _iStdErr = iStdErr[0];
        _oStdIn = ::fdopen (_iStdIn, Text ("w"));
        _oStdOut = ::fdopen (_iStdOut, Text ("r"));
        _oStdErr = ::fdopen (_iStdErr, Text ("r"));
        _bStarted = _bRunning = true;
        // Save command and args and the rest of the fields in data members
        return true;
    }
    else if (iPID == 0)
    {
        // Child process
        // Close unnecessary pipe endpoints
        ::close (iStdIn[1]);
        ::close (iStdOut[0]);
        ::close (iStdErr[0]);
        // Change directory
        if (!_sExecDir.IsEmpty ())
            ::chdir (_sExecDir);
        // Execute command
        if (_bExecInShell)
        {
            // Execute the command '/bin/sh' with arguments
            //  'sh', '-c', cmd, arg1, arg2, ..., argN
            //...
            execvp (sCmd, paArgs);
        }
        else
        {
            // Create arguments (1st argument is the command basename)
            //...
            ::execvp (sCmd, paArgs);
        }
        ::_exit (1);
    }
    ...
    // If errors cleaning up.

method isRunning
Here is where I have some doubts (Initially I set the flags WUNTRACED and WCONTINUED as in susv4tc1, waitpid example. Now commented out).
Code:
    if (_bStarted && _bRunning)
    {
        Int iStatus = IDNull;
        Int iPID = waitpid (_iPID, &iStatus, WNOHANG); //WNOHANG | WEXITED |
                                                       //WUNTRACED | WCONTINUED);
        if (WIFEXITED (iStatus) || WIFSIGNALED (iStatus) || (iPID == IDNull))
            _bRunning = false;
    }
    return _bRunning;

method Out
Reading stdout
Code:
    String sText = Text ("");
    if (_bStarted && (!::feof (_oStdOut)))
    {
        // Buffer 1 kB (>>> move to class data members <<<)
        Int iLength = KiB;
        Char psText[iLength + 1];
        psText[iLength] = Text ('\0');
        Char * psResult = ::fgets (psText, iLength, _oStdOut);
        if (psResult)
            sText = psText;
        else
        {
            // XXX: DEBUG
            //boost::system::error_code oError (errno, boost::system::system_category ());
            Int iResult = errno;
std::cout << "OUT ERROR: " << iResult << std::endl;
        }
    }
    return sText;

The Wait method close all pipes, call waitpid with flags set to 0 and clean up the object.

Using it
Code:
    Process oProc;
    Array<String> aArgs;
    aArgs.Add (Text ("-lohAFGH"));
    aArgs.Add (Text ("-D"));
    aArgs.Add (Text ("%Y.%m.%d %H:%M"));
    aArgs.Add (Text ("/usr/local"));
    if (oProc.Start (Text ("ls"), aArgs))
    {
        String s;
        Int iTimeout = 100;
        bool bRunning = true;
        while (bRunning)
        {
        //while (oProc.IsRunning ())
        //{
            bRunning = oProc.IsRunning ();
            s = oProc.Out ();
            if (!s.IsEmpty ())
            {
                Msg (s);
                bRunning = true;
            }
            s = oProc.Err ();
            if (!s.IsEmpty ())
            {
                MsgReset (ConsoleColor::Red, s);
                bRunning = true;
            }
        }
        oProc.Wait ();
    }
 
I need a break, a long break. I compiled this...this

Code:
int
main (int argc, char * argv[])
{
	string s ("abcd1234\n");
	cout << s << s;
	return 0;
}

a very simple program and the output is what I expect

Code:
abcd1234
abcd1234

not

Code:
abcd1234
        abcd1234

Now, where I'm testing Process class I'm using ncurses in a strange way. The ncurses initialization and termination code is

Code:
void
InitCurses ()
{
    _pStdIn = ::fdopen (STDIN_FILENO, "r");
    _pStdOut = ::fdopen (STDOUT_FILENO, "w");
    _pScreen = NCurses::newterm (NULL, _pStdIn, _pStdOut);
    // Colors
    NCurses::start_color ();
#if !defined (DEBUG)
    // This kill NetBeans debugger
    _bMono = !NCurses::has_colors ();
#endif
    _iColorCount = NCurses::COLORS;
}

void
UninitCurses ()
{
    NCurses::endwin ();
    NCurses::delscreen (_pScreen);
    ::fclose (_pStdIn);
    ::fclose (_pStdOut);
}

I use newtem instead of initscr to prevent clearing the screen and main ncurses window wrapper, in fact to write a line I must write

Code:
cout << sText << "\r\n";

The Process class is working (more or less).
 
All is working, the source files were full of errors (ncurses) from ages, I wrote the code few years ago and never seriously look at it. One for all

Code:
_pScreen = NCurses::newterm (NULL, _pStdIn, _pStdOut);

instead of

Code:
_pScreen = NCurses::newterm (NULL, _pStdOut, _pStdIn);

however, output text with std::cout still require "\r\n" for newlines, mixing printw with std::cout is not recommended, when closing ncurses it leaves blank lines beetwen last written line and the shell prompt, keypad function only work with a WINDOW object.
 
Back
Top