PTEXT SplitLine( PTEXT pLine, INDEX nPos ) { PTEXT newseg, end; if( !nPos ) { if( PRIORLINE( pLine ) ) return PRIORLINE( pLine ); // otherwise we'll have to insert a new segment // in front of this.... newseg = SegCreate( BUILD_LINE_OUTPUT_SIZE ); newseg->data.size = 0; pLine->format.position.offset.spaces = 0; SegAppend( newseg, pLine ); return newseg; } else if( pLine->data.size == nPos ) { // if the point to split is not in the middle of // this segment.... return pLine; } newseg = SegCreate( BUILD_LINE_OUTPUT_SIZE ); end = NEXTLINE( pLine ); SegBreak( end ); // fill in new segment with trailing data newseg->data.size = pLine->data.size - nPos; MemCpy( newseg->data.data, pLine->data.data + nPos, newseg->data.size ); pLine->data.size = nPos; pLine->data.data[nPos] = 0; // terminate with null also... SegAppend( pLine , SegAppend( newseg, end ) ); return pLine; }
PTEXT win_get_line(HANDLE hFile) { // extern HANDLE hStdin; #define WORKSPACE 1024 // character for workspace PTEXT workline=(PTEXT)NULL; uint32_t length = 0; do { // create a workspace to read input from the file. workline=SegAppend(workline,SegCreate(WORKSPACE)); SetEnd( workline ); // read a line of input from the file. if( !ReadConsole( hFile , GetText(workline) , WORKSPACE , &length , NULL) ) // if no input read. { if (PRIORLINE(workline)) // if we've read some. { PTEXT t; workline=PRIORLINE(workline); // go back one. SegBreak(t = NEXTLINE(workline)); LineRelease(t); // destroy the current segment. } else { LineRelease(workline); // destory only segment. workline = NULL; } break; // get out of the loop- there is no more to read. } } while (GetText(workline)[length-1]!='\n'); //while not at the end of the line. if (workline&&length) // if I got a line, and there was some length to it. SetStart(workline); // set workline to the beginning. return(workline); // return the line read from the file. }
static uintptr_t CPROC HandleTaskOutput(PTHREAD thread ) { PTASK_INFO task = (PTASK_INFO)GetThreadParam( thread ); { task->pOutputThread = thread; // read input from task, montiro close and dispatch TaskEnd Notification also. { PHANDLEINFO phi = &task->hStdOut; PTEXT pInput = SegCreate( 4096 ); int done, lastloop; Hold( task ); done = lastloop = FALSE; do { uint32_t dwRead, dwAvail; if( done ) lastloop = TRUE; #ifdef _WIN32 //while( ) { #else while( CanRead( phi->handle ) ) #endif { if( task->flags.log_input ) lprintf( WIDE( "Go to read task's stdout." ) ); #ifdef _WIN32 if( !task->flags.process_ended && ReadFile( phi->handle , GetText( pInput ), (DWORD)(GetTextSize( pInput ) - 1) , (LPDWORD)&dwRead, NULL ) ) //read the pipe { #else dwRead = read( phi->handle , GetText( pInput ) , GetTextSize( pInput ) - 1 ); if( !dwRead ) { #ifdef _DEBUG //lprintf( WIDE( "Ending system thread because of broke pipe! %d" ), errno ); #endif #ifdef WIN32 continue; #else //lprintf( WIDE( "0 read = pipe failure." ) ); break; #endif } #endif if( task->flags.log_input ) lprintf( WIDE( "got read on task's stdout: %d" ), dwRead ); if( task->flags.bSentIoTerminator ) { if( dwRead > 1 ) dwRead--; else { if( task->flags.log_input ) lprintf( WIDE( "Finished, no more data, task has ended; no need for once more around" ) ); lastloop = 1; break; // we're done; task ended, and we got an io terminator on XP } } //lprintf( WIDE( "result %d" ), dwRead ); GetText( pInput )[dwRead] = 0; pInput->data.size = dwRead; //LogBinary( GetText( pInput ), GetTextSize( pInput ) ); if( task->OutputEvent ) { task->OutputEvent( task->psvEnd, task, GetText( pInput ), GetTextSize( pInput ) ); } pInput->data.size = 4096; #ifdef _WIN32 } else { DWORD dwError = GetLastError(); if( ( dwError == ERROR_OPERATION_ABORTED ) && task->flags.process_ended ) { if( PeekNamedPipe( phi->handle, NULL, 0, NULL, (LPDWORD)&dwAvail, NULL ) ) { if( dwAvail > 0 ) { lprintf( WIDE( "caught data" ) ); // there is still data in the pipe, just that the process closed // and we got the sync even before getting the data. } else break; } } } #endif } #ifdef _WIN32 } #endif //allow a minor time for output to be gathered before sending // partial gathers... if( task->flags.process_ended ) #ifdef _WIN32 { // Ending system thread because of process exit! done = TRUE; } #else //if( !dwRead ) // break; if( task->pid == waitpid( task->pid, NULL, WNOHANG ) ) { Log( WIDE( "Setting done event on system reader." ) ); done = TRUE; // do one pass to make sure we completed read } else { //lprintf( WIDE( "process active..." ) ); Relinquish(); } #endif } while( !lastloop ); #ifdef _DEBUG if( lastloop ) { //DECLTEXT( msg, WIDE( "Ending system thread because of process exit!" ) ); //EnqueLink( phi->pdp->&ps->Command->Output, &msg ); } else { //DECLTEXT( msg, WIDE( "Guess we exited from broken pipe" ) ); //EnqueLink( phi->pdp->&ps->Command->Output, &msg ); } #endif LineRelease( pInput ); #ifdef _WIN32 CloseHandle( task->hReadIn ); CloseHandle( task->hReadOut ); CloseHandle( task->hWriteIn ); CloseHandle( task->hWriteOut ); //lprintf( WIDE( "Closing process handle %p" ), task->pi.hProcess ); phi->hThread = 0; #else //close( phi->handle ); close( task->hStdIn.pair[1] ); close( task->hStdOut.pair[0] ); //close( task->hStdErr.pair[0] ); #define INVALID_HANDLE_VALUE -1 #endif if( phi->handle == task->hStdIn.handle ) task->hStdIn.handle = INVALID_HANDLE_VALUE; phi->handle = INVALID_HANDLE_VALUE; task->pOutputThread = NULL; Release( task ); //WakeAThread( phi->pdp->common.Owner ); return 0xdead; } } }
static PTEXT CPROC ParseCommand( PMYDATAPATH pdp, PTEXT buffer ) { if( buffer ) { PTEXT pCommand; //Log2( WIDE("buffer: %s(%d)"), GetText( buffer ), GetTextSize( buffer ) ); //LogBinary( buffer ); pCommand = burst( buffer ); LineRelease( buffer ); if( pCommand ) { PTEXT pTemp, pStart; int bEscaped = FALSE; pStart = pTemp = pCommand; while( pTemp ) { if( TextIs( pTemp, WIDE("\\") ) ) { if( !bEscaped ) { PTEXT pNext; pNext = NEXTLINE( pTemp ); pNext->format.position.offset.spaces = pTemp->format.position.offset.spaces; LineRelease( SegGrab( pTemp ) ); bEscaped = TRUE; pTemp = pNext; continue; } } if( !bEscaped && TextIs( pTemp, WIDE(";") ) ) { PTEXT pPrior; //Log( WIDE("Splitting the line and enqueing it...") ); pPrior = pTemp; SegBreak( pTemp ); if( pStart != pTemp ) { // end of line included! pStart = SegAppend( pStart, SegCreate(0) ); EnqueLink( &pdp->output, pStart ); } pStart = pTemp = NEXTLINE( pTemp ); SegBreak( pTemp ); LineRelease( pPrior ); // remove ';' bEscaped = FALSE; continue; } bEscaped = FALSE; pTemp = NEXTLINE( pTemp ); } if( pStart ) { PTEXT line; line = BuildLine( pStart ); //Log1( WIDE("Enqueu: %s"), GetText( line ) ); LineRelease( line ); EnqueLink( &pdp->output, pStart ); } } else { // well what now? I guess pLine got put into Partial... // next pass through this all for command recall will blow... Log( WIDE("No information from the burst!") ); } } return (PTEXT)DequeLink( &pdp->output ); }
CORE_PROC( PTEXT, GatherLineEx )( PTEXT *pOutput, INDEX *pIndex, int bInsert, int bSaveCR, int bData, PTEXT pInput ) // if data - assume data is coming from a preformatted source // otherwise use escape as command entry and clear buffer... { // this routine should be used to process user type character // input into a legible line buffer.... // results in a complete line.... // the line returned must be used - the output buffer // is an accumulator and will contain any partial input buffer // which remaineder if an EOL sequence was found.... // build line in buffer using standard console // behavior... INDEX pos , len = 0 , size , maxlen = 0; PTEXT pReturn = NULL; PTEXT pDelete = NULL; TEXTCHAR character; TEXTSTR output; if( !pOutput ) // must supply a holder for partial collection... return NULL; if( !pInput ) // nothing new input - just using previous collection... { if( *pOutput ) { // use prior partial as new input.... pInput = *pOutput; pDelete = pInput; // this is never deleted if we use prior... SetStart( pInput ); *pOutput = NULL; } else return NULL; } // probably first pass of gathering... if( !*pOutput ) { *pOutput = SegCreate( BUILD_LINE_OUTPUT_SIZE ); if( pIndex ) *pIndex = 0; SetTextSize( *pOutput, 0 ); output = GetText( *pOutput ); len = 0; } else if( pIndex ) { output = GetText( *pOutput ); len = *pIndex; if( (*pOutput)->data.size != len ) { if( bInsert ) { // creates a new segment inbetween here..... *pOutput = SplitLine( *pOutput, *pIndex ); output = GetText( *pOutput ); len = *pIndex = GetTextSize( *pOutput ); } else { maxlen = (*pOutput)->data.size; } } } else { output = GetText( *pOutput ); len = GetTextSize( *pOutput ); } while( pInput ) { size = GetTextSize( pInput ); for( pos = 0; pos < size; pos++ ) { switch( character = GetText( pInput )[pos] ) { case '\x1b': if( !bData ) { SetEnd( *pOutput ); SetStart( *pOutput ) { SetTextSize( *pOutput, 0 ); } SetTextSize( *pOutput, 0 ); output = GetText( *pOutput ); len = 0; } else goto defaultcase; break; case '\x7f': // handle unix type delete too ? perhaps... if( !bInsert ) { PTEXT pNext; // this will slide from the middle to the end... // if bInsert - then prior to entrying this switch // the data was split and THIS segment is set to zero. pNext = *pOutput; if( len != (maxlen = GetTextSize( *pOutput )) ) { MemCpy( output + len, output+len+1, maxlen - len ); SetTextSize( *pOutput, --maxlen ); } else { PTEXT pDel; pNext = *pOutput; do { pDel = pNext; pNext = NEXTLINE( pNext ); if( pDel != *pOutput ) { SegGrab( pDel ); LineRelease( pDel ); } } while( pNext && !GetTextSize( pNext ) ); if( pNext ) { size_t len2; output = GetText( pNext ); len2 = GetTextSize( pNext ) - 1; *pOutput = pNext; len = 0; MemCpy( output, output+1, len2 ); SetTextSize( pNext, len2 ); } } } else // was insert is either at end.... { // I dunno perform sliding delete operation... // must refresh the output string.... { PTEXT pNext, pDel; pNext = *pOutput; do { pDel = pNext; pNext = NEXTLINE( pNext ); if( pDel != *pOutput ) { SegGrab( pDel ); LineRelease( pDel ); } } while( pNext && !GetTextSize( pNext ) ); if( pNext ) { size_t len2; TEXTCHAR *data; data = GetText( pNext ); MemCpy( data, data+1, len2 = (GetTextSize( pNext ) - 1 )); SetTextSize( pNext, len2 ); } } } break; case '\b': /* perhaps consider using split for backspace in a line...*/ if( !bInsert ) { PTEXT pNext; size_t maxlen; // this will slide from the middle to the end... // if bInsert - then prior to entrying this switch // the data was split and THIS segment is set to zero. pNext = *pOutput; maxlen = GetTextSize( *pOutput ); while( !maxlen && PRIORLINE( *pOutput ) ) { *pOutput = PRIORLINE( *pOutput ); len = maxlen = GetTextSize( *pOutput ); } if( maxlen ) { if( len != maxlen ) { size_t sz; sz = maxlen - len; MemCpy( output + len - 1, output + len, sz ); SetTextSize( *pOutput, maxlen - 1 ); len--; } else { SetTextSize( *pOutput, --len ); } } } else // was insert is either at end.... { if( len ) { SetTextSize( *pOutput, --len ); } else { if( PRIORLINE( *pOutput ) ) { *pOutput = PRIORLINE( *pOutput ); len = GetTextSize( *pOutput ); } if( len ) SetTextSize( *pOutput, --len ); } } break; case '\r': // ignore this character... if( !bSaveCR ) break; // falls through .. past this and saves the return... if(0) case '\n': if( !pReturn ) { // transfer *pOutput to pReturn.... pReturn = *pOutput; SetEnd( pReturn ); output = GetText( pReturn ); len = GetTextSize( pReturn ); output[len] = character; SetTextSize( pReturn, ++len ); // begin next collection in case more data is in the input... *pOutput = SegCreate( BUILD_LINE_OUTPUT_SIZE ); SetTextSize( *pOutput, 0 ); output = GetText( *pOutput ); len = 0; break; } // store carriage return... default: defaultcase: output[len++] = character; if( (maxlen && len == maxlen ) || len == BUILD_LINE_OUTPUT_SIZE ) { PTEXT pTemp; SetTextSize( *pOutput, len ); if( !NEXTLINE( *pOutput ) ) { SegAppend( *pOutput, pTemp = SegCreate( BUILD_LINE_OUTPUT_SIZE ) ); SetTextSize( pTemp, 0 ); } else { pTemp = NEXTLINE( *pOutput ); maxlen = GetTextSize( pTemp ); } *pOutput = pTemp; output = GetText( *pOutput ); len = 0; } else { if( bInsert ) // insertion happens at end of segment // and the segment is broken... { if( !pIndex || ( len > *pIndex ) ) SetTextSize( *pOutput, len ); } else if( len > GetTextSize( *pOutput ) ) { SetTextSize( *pOutput, len ); } } break; } }