xref: /core/basic/source/runtime/iosys.cxx (revision 7af90cc9)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <string.h>
21 #include <vcl/svapp.hxx>
22 #include <vcl/weld.hxx>
23 #include <osl/file.hxx>
24 #include <tools/urlobj.hxx>
25 
26 #include <runtime.hxx>
27 
28 #include <rtl/byteseq.hxx>
29 #include <rtl/textenc.h>
30 #include <rtl/strbuf.hxx>
31 #include <rtl/ustrbuf.hxx>
32 #include <sal/log.hxx>
33 
34 #include <comphelper/processfactory.hxx>
35 #include <comphelper/string.hxx>
36 
37 #include <com/sun/star/bridge/BridgeFactory.hpp>
38 #include <com/sun/star/bridge/XBridge.hpp>
39 #include <com/sun/star/uno/Sequence.hxx>
40 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
41 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
42 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
43 #include <com/sun/star/ucb/XContentProvider.hpp>
44 #include <com/sun/star/ucb/XContentProviderManager.hpp>
45 #include <com/sun/star/io/XInputStream.hpp>
46 #include <com/sun/star/io/XOutputStream.hpp>
47 #include <com/sun/star/io/XStream.hpp>
48 #include <com/sun/star/io/XSeekable.hpp>
49 
50 using namespace com::sun::star::uno;
51 using namespace com::sun::star::lang;
52 using namespace com::sun::star::ucb;
53 using namespace com::sun::star::io;
54 using namespace com::sun::star::bridge;
55 
56 #include <iosys.hxx>
57 #include <sbintern.hxx>
58 
59 
60 class SbiInputDialog : public weld::GenericDialogController
61 {
62     std::unique_ptr<weld::Entry> m_xInput;
63     std::unique_ptr<weld::Button> m_xOk;
64     std::unique_ptr<weld::Button> m_xCancel;
65     std::unique_ptr<weld::Label> m_xPromptText;
66     OUString m_aText;
67     DECL_LINK(Ok, weld::Button&, void);
68     DECL_LINK(Cancel, weld::Button&, void);
69 public:
70     SbiInputDialog(weld::Window*, const OUString&);
71     const OUString& GetInput() { return m_aText; }
72 };
73 
74 SbiInputDialog::SbiInputDialog(weld::Window* pParent, const OUString& rPrompt)
75     : GenericDialogController(pParent, "svt/ui/inputbox.ui", "InputBox")
76     , m_xInput(m_xBuilder->weld_entry("entry"))
77     , m_xOk(m_xBuilder->weld_button("ok"))
78     , m_xCancel(m_xBuilder->weld_button("cancel"))
79     , m_xPromptText(m_xBuilder->weld_label("prompt"))
80 {
81     m_xDialog->set_title(rPrompt);
82     m_xPromptText->set_label(rPrompt);
83     m_xOk->connect_clicked( LINK( this, SbiInputDialog, Ok ) );
84     m_xCancel->connect_clicked( LINK( this, SbiInputDialog, Cancel ) );
85 }
86 
87 IMPL_LINK_NOARG( SbiInputDialog, Ok, weld::Button&, void )
88 {
89     m_aText = m_xInput->get_text();
90     m_xDialog->response(RET_OK);
91 }
92 
93 IMPL_LINK_NOARG( SbiInputDialog, Cancel, weld::Button&, void )
94 {
95     m_xDialog->response(RET_CANCEL);
96 }
97 
98 SbiStream::SbiStream()
99     : pStrm(nullptr)
100     , nExpandOnWriteTo(0)
101     , nLine(0)
102     , nLen(0)
103     , nMode(SbiStreamFlags::NONE)
104     , nError(0)
105 {
106 }
107 
108 SbiStream::~SbiStream()
109 {
110 }
111 
112 // map an SvStream-error to StarBASIC-code
113 
114 void SbiStream::MapError()
115 {
116     if( pStrm )
117     {
118         ErrCode nEC = pStrm->GetError();
119         if (nEC == ERRCODE_NONE)
120             nError = ERRCODE_NONE;
121         else if (nEC == SVSTREAM_FILE_NOT_FOUND)
122             nError = ERRCODE_BASIC_FILE_NOT_FOUND;
123         else if (nEC ==SVSTREAM_PATH_NOT_FOUND)
124             nError = ERRCODE_BASIC_PATH_NOT_FOUND;
125         else if (nEC ==SVSTREAM_TOO_MANY_OPEN_FILES)
126             nError = ERRCODE_BASIC_TOO_MANY_FILES;
127         else if (nEC ==SVSTREAM_ACCESS_DENIED)
128             nError = ERRCODE_BASIC_ACCESS_DENIED;
129         else if (nEC ==SVSTREAM_INVALID_PARAMETER)
130             nError = ERRCODE_BASIC_BAD_ARGUMENT;
131         else if (nEC ==SVSTREAM_OUTOFMEMORY)
132             nError = ERRCODE_BASIC_NO_MEMORY;
133         else
134             nError = ERRCODE_BASIC_IO_ERROR;
135     }
136 }
137 
138 // Returns sal_True if UNO is available, otherwise the old file
139 // system implementation has to be used
140 // #89378 New semantic: Don't just ask for UNO but for UCB
141 bool hasUno()
142 {
143     static bool bNeedInit = true;
144     static bool bRetVal = true;
145 
146     if( bNeedInit )
147     {
148         bNeedInit = false;
149         Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
150         if( !xContext.is() )
151         {
152             // No service manager at all
153             bRetVal = false;
154         }
155         else
156         {
157             Reference< XUniversalContentBroker > xManager = UniversalContentBroker::create(xContext);
158 
159             if ( !( xManager->queryContentProvider( "file:///" ).is() ) )
160             {
161                 // No UCB
162                 bRetVal = false;
163             }
164         }
165     }
166     return bRetVal;
167 }
168 
169 
170 class OslStream : public SvStream
171 {
172     osl::File maFile;
173 
174 public:
175                         OslStream( const OUString& rName, StreamMode nStrmMode );
176                        virtual ~OslStream() override;
177     virtual std::size_t GetData(void* pData, std::size_t nSize) override;
178     virtual std::size_t PutData(const void* pData, std::size_t nSize) override;
179     virtual sal_uInt64 SeekPos( sal_uInt64 nPos ) override;
180     virtual void        FlushData() override;
181     virtual void        SetSize( sal_uInt64 nSize) override;
182 };
183 
184 OslStream::OslStream( const OUString& rName, StreamMode nStrmMode )
185     : maFile( rName )
186 {
187     sal_uInt32 nFlags;
188 
189     if( (nStrmMode & (StreamMode::READ | StreamMode::WRITE)) == (StreamMode::READ | StreamMode::WRITE) )
190     {
191         nFlags = osl_File_OpenFlag_Read | osl_File_OpenFlag_Write;
192     }
193     else if( nStrmMode & StreamMode::WRITE )
194     {
195         nFlags = osl_File_OpenFlag_Write;
196     }
197     else //if( nStrmMode & StreamMode::READ )
198     {
199         nFlags = osl_File_OpenFlag_Read;
200     }
201 
202     osl::FileBase::RC nRet = maFile.open( nFlags );
203     if( nRet == osl::FileBase::E_NOENT && nFlags != osl_File_OpenFlag_Read )
204     {
205         nFlags |= osl_File_OpenFlag_Create;
206         nRet = maFile.open( nFlags );
207     }
208 
209     if( nRet != osl::FileBase::E_None )
210     {
211         SetError( ERRCODE_IO_GENERAL );
212     }
213 }
214 
215 
216 OslStream::~OslStream()
217 {
218     maFile.close();
219 }
220 
221 std::size_t OslStream::GetData(void* pData, std::size_t nSize)
222 {
223     sal_uInt64 nBytesRead = nSize;
224     maFile.read( pData, nBytesRead, nBytesRead );
225     return nBytesRead;
226 }
227 
228 std::size_t OslStream::PutData(const void* pData, std::size_t nSize)
229 {
230     sal_uInt64 nBytesWritten;
231     maFile.write( pData, nSize, nBytesWritten );
232     return nBytesWritten;
233 }
234 
235 sal_uInt64 OslStream::SeekPos( sal_uInt64 nPos )
236 {
237     ::osl::FileBase::RC rc = ::osl::FileBase::E_None;
238     // check if a truncated STREAM_SEEK_TO_END was passed
239     assert(nPos != SAL_MAX_UINT32);
240     if( nPos == STREAM_SEEK_TO_END )
241     {
242         rc = maFile.setPos( osl_Pos_End, 0 );
243     }
244     else
245     {
246         rc = maFile.setPos( osl_Pos_Absolut, nPos );
247     }
248     OSL_VERIFY(rc == ::osl::FileBase::E_None);
249     sal_uInt64 nRealPos(0);
250     maFile.getPos( nRealPos );
251     return nRealPos;
252 }
253 
254 void OslStream::FlushData()
255 {
256 }
257 
258 void OslStream::SetSize( sal_uInt64 nSize )
259 {
260     maFile.setSize( nSize );
261 }
262 
263 
264 class UCBStream : public SvStream
265 {
266     Reference< XInputStream >   xIS;
267     Reference< XStream >        xS;
268     Reference< XSeekable >      xSeek;
269 public:
270     explicit UCBStream( Reference< XInputStream > const & xIS );
271     explicit UCBStream( Reference< XStream > const & xS );
272                        virtual ~UCBStream() override;
273     virtual std::size_t GetData( void* pData, std::size_t nSize ) override;
274     virtual std::size_t PutData( const void* pData, std::size_t nSize ) override;
275     virtual sal_uInt64 SeekPos( sal_uInt64 nPos ) override;
276     virtual void        FlushData() override;
277     virtual void        SetSize( sal_uInt64 nSize ) override;
278 };
279 
280 UCBStream::UCBStream( Reference< XInputStream > const & rStm )
281     : xIS( rStm )
282     , xSeek( rStm, UNO_QUERY )
283 {
284 }
285 
286 UCBStream::UCBStream( Reference< XStream > const & rStm )
287     : xS( rStm )
288     , xSeek( rStm, UNO_QUERY )
289 {
290 }
291 
292 
293 UCBStream::~UCBStream()
294 {
295     try
296     {
297         if( xIS.is() )
298         {
299             xIS->closeInput();
300         }
301         else if( xS.is() )
302         {
303             Reference< XInputStream > xIS_ = xS->getInputStream();
304             if( xIS_.is() )
305             {
306                 xIS_->closeInput();
307             }
308         }
309     }
310     catch(const Exception & )
311     {
312         SetError( ERRCODE_IO_GENERAL );
313     }
314 }
315 
316 std::size_t UCBStream::GetData(void* pData, std::size_t nSize)
317 {
318     try
319     {
320         Reference< XInputStream > xISFromS;
321         if( xIS.is() )
322         {
323             Sequence<sal_Int8> aData;
324             nSize = xIS->readBytes( aData, nSize );
325             memcpy( pData, aData.getConstArray(), nSize );
326             return nSize;
327         }
328         else if( xS.is() && (xISFromS = xS->getInputStream()).is() )
329         {
330             Sequence<sal_Int8> aData;
331             nSize = xISFromS->readBytes( aData, nSize );
332             memcpy(pData, aData.getConstArray(), nSize );
333             return nSize;
334         }
335         else
336         {
337             SetError( ERRCODE_IO_GENERAL );
338         }
339     }
340     catch(const Exception & )
341     {
342         SetError( ERRCODE_IO_GENERAL );
343     }
344     return 0;
345 }
346 
347 std::size_t UCBStream::PutData(const void* pData, std::size_t nSize)
348 {
349     try
350     {
351         Reference< XOutputStream > xOSFromS;
352         if( xS.is() && (xOSFromS = xS->getOutputStream()).is() )
353         {
354             Sequence<sal_Int8> aData( static_cast<const sal_Int8 *>(pData), nSize );
355             xOSFromS->writeBytes( aData );
356             return nSize;
357         }
358         else
359         {
360             SetError( ERRCODE_IO_GENERAL );
361         }
362     }
363     catch(const Exception & )
364     {
365         SetError( ERRCODE_IO_GENERAL );
366     }
367     return 0;
368 }
369 
370 sal_uInt64 UCBStream::SeekPos( sal_uInt64 nPos )
371 {
372     try
373     {
374         if( xSeek.is() )
375         {
376             sal_uInt64 nLen = static_cast<sal_uInt64>( xSeek->getLength() );
377             if( nPos > nLen )
378             {
379                 nPos = nLen;
380             }
381             xSeek->seek( nPos );
382             return nPos;
383         }
384         else
385         {
386             SetError( ERRCODE_IO_GENERAL );
387         }
388     }
389     catch(const Exception & )
390     {
391         SetError( ERRCODE_IO_GENERAL );
392     }
393     return 0;
394 }
395 
396 void UCBStream::FlushData()
397 {
398     try
399     {
400         Reference< XOutputStream > xOSFromS;
401         if( xS.is() && (xOSFromS = xS->getOutputStream()).is() )
402         {
403             xOSFromS->flush();
404         }
405         else
406         {
407             SetError( ERRCODE_IO_GENERAL );
408         }
409     }
410     catch(const Exception & )
411     {
412         SetError( ERRCODE_IO_GENERAL );
413     }
414 }
415 
416 void    UCBStream::SetSize( sal_uInt64 )
417 {
418     SAL_WARN("basic", "UCBStream::SetSize not allowed to call from basic" );
419     SetError( ERRCODE_IO_GENERAL );
420 }
421 
422 
423 ErrCode const & SbiStream::Open
424 ( const OString& rName, StreamMode nStrmMode, SbiStreamFlags nFlags, short nL )
425 {
426     nMode   = nFlags;
427     nLen    = nL;
428     nLine   = 0;
429     nExpandOnWriteTo = 0;
430     if( ( nStrmMode & ( StreamMode::READ|StreamMode::WRITE ) ) == StreamMode::READ )
431     {
432         nStrmMode |= StreamMode::NOCREATE;
433     }
434     OUString aStr(OStringToOUString(rName, osl_getThreadTextEncoding()));
435     OUString aNameStr = getFullPath( aStr );
436 
437     if( hasUno() )
438     {
439         Reference< XSimpleFileAccess3 > xSFI( SimpleFileAccess::create( comphelper::getProcessComponentContext() ) );
440         try
441         {
442 
443         // #??? For write access delete file if it already exists (not for appending)
444         if( (nStrmMode & StreamMode::WRITE) && !IsAppend() && !IsBinary() && !IsRandom() &&
445             xSFI->exists( aNameStr ) && !xSFI->isFolder( aNameStr ) )
446         {
447             xSFI->kill( aNameStr );
448         }
449 
450         if( (nStrmMode & (StreamMode::READ | StreamMode::WRITE)) == (StreamMode::READ | StreamMode::WRITE) )
451         {
452             Reference< XStream > xIS = xSFI->openFileReadWrite( aNameStr );
453             pStrm.reset( new UCBStream( xIS ) );
454         }
455         else if( nStrmMode & StreamMode::WRITE )
456         {
457             Reference< XStream > xIS = xSFI->openFileReadWrite( aNameStr );
458             pStrm.reset( new UCBStream( xIS ) );
459         }
460         else //if( nStrmMode & StreamMode::READ )
461         {
462             Reference< XInputStream > xIS = xSFI->openFileRead( aNameStr );
463             pStrm.reset( new UCBStream( xIS ) );
464         }
465 
466         }
467         catch(const Exception & )
468         {
469             nError = ERRCODE_IO_GENERAL;
470         }
471     }
472 
473     if( !pStrm )
474     {
475         pStrm.reset( new OslStream( aNameStr, nStrmMode ) );
476     }
477     if( IsAppend() )
478     {
479         pStrm->Seek( STREAM_SEEK_TO_END );
480     }
481     MapError();
482     if( nError )
483     {
484         pStrm.reset();
485     }
486     return nError;
487 }
488 
489 ErrCode const & SbiStream::Close()
490 {
491     if( pStrm )
492     {
493         MapError();
494         pStrm.reset();
495     }
496     return nError;
497 }
498 
499 ErrCode SbiStream::Read(OString& rBuf, sal_uInt16 n, bool bForceReadingPerByte)
500 {
501     nExpandOnWriteTo = 0;
502     if( !bForceReadingPerByte && IsText() )
503     {
504         pStrm->ReadLine(rBuf);
505         nLine++;
506     }
507     else
508     {
509         if( !n )
510         {
511             n = nLen;
512         }
513         if( !n )
514         {
515             return nError = ERRCODE_BASIC_BAD_RECORD_LENGTH;
516         }
517         OStringBuffer aBuffer(read_uInt8s_ToOString(*pStrm, n));
518         //Pad it out with ' ' to the requested length on short read
519         sal_Int32 nRequested = sal::static_int_cast<sal_Int32>(n);
520         comphelper::string::padToLength(aBuffer, nRequested, ' ');
521         rBuf = aBuffer.makeStringAndClear();
522     }
523     MapError();
524     if( !nError && pStrm->eof() )
525     {
526         nError = ERRCODE_BASIC_READ_PAST_EOF;
527     }
528     return nError;
529 }
530 
531 ErrCode const & SbiStream::Read( char& ch )
532 {
533     nExpandOnWriteTo = 0;
534     if (aLine.isEmpty())
535     {
536         Read( aLine );
537         aLine = aLine + OString('\n');
538     }
539     ch = aLine[0];
540     aLine = aLine.copy(1);
541     return nError;
542 }
543 
544 void SbiStream::ExpandFile()
545 {
546     if ( nExpandOnWriteTo )
547     {
548         sal_uInt64 nCur = pStrm->Seek(STREAM_SEEK_TO_END);
549         if( nCur < nExpandOnWriteTo )
550         {
551             sal_uInt64 nDiff = nExpandOnWriteTo - nCur;
552             while( nDiff-- )
553             {
554                 pStrm->WriteChar( 0 );
555             }
556         }
557         else
558         {
559             pStrm->Seek( nExpandOnWriteTo );
560         }
561         nExpandOnWriteTo = 0;
562     }
563 }
564 
565 namespace
566 {
567     void WriteLines(SvStream &rStream, const OString& rStr)
568     {
569         OString aStr(convertLineEnd(rStr, rStream.GetLineDelimiter()) );
570         write_uInt8s_FromOString(rStream, aStr);
571         endl( rStream );
572     }
573 }
574 
575 ErrCode SbiStream::Write( const OString& rBuf )
576 {
577     ExpandFile();
578     if( IsAppend() )
579     {
580         pStrm->Seek( STREAM_SEEK_TO_END );
581     }
582     if( IsText() )
583     {
584         aLine = aLine + rBuf;
585         // Get it out, if the end is an LF, but strip CRLF before,
586         // because the SvStream adds a CRLF!
587         sal_Int32 nLineLen = aLine.getLength();
588         if (nLineLen && aLine[--nLineLen] == 0x0A)
589         {
590             aLine = aLine.copy(0, nLineLen);
591             if (nLineLen && aLine[--nLineLen] == 0x0D)
592             {
593                 aLine = aLine.copy(0, nLineLen);
594             }
595             WriteLines(*pStrm, aLine);
596             aLine.clear();
597         }
598     }
599     else
600     {
601         if( !nLen )
602         {
603             return nError = ERRCODE_BASIC_BAD_RECORD_LENGTH;
604         }
605         pStrm->WriteBytes(rBuf.getStr(), nLen);
606         MapError();
607     }
608     return nError;
609 }
610 
611 
612 SbiIoSystem::SbiIoSystem()
613 {
614     for(SbiStream* & i : pChan)
615     {
616         i = nullptr;
617     }
618     nChan  = 0;
619     nError = ERRCODE_NONE;
620 }
621 
622 SbiIoSystem::~SbiIoSystem() COVERITY_NOEXCEPT_FALSE
623 {
624     Shutdown();
625 }
626 
627 ErrCode SbiIoSystem::GetError()
628 {
629     ErrCode n = nError;
630     nError = ERRCODE_NONE;
631     return n;
632 }
633 
634 void SbiIoSystem::Open(short nCh, const OString& rName, StreamMode nMode, SbiStreamFlags nFlags, short nLen)
635 {
636     nError = ERRCODE_NONE;
637     if( nCh >= CHANNELS || !nCh )
638     {
639         nError = ERRCODE_BASIC_BAD_CHANNEL;
640     }
641     else if( pChan[ nCh ] )
642     {
643         nError = ERRCODE_BASIC_FILE_ALREADY_OPEN;
644     }
645     else
646     {
647        pChan[ nCh ] = new SbiStream;
648        nError = pChan[ nCh ]->Open( rName, nMode, nFlags, nLen );
649        if( nError )
650        {
651             delete pChan[ nCh ];
652             pChan[ nCh ] = nullptr;
653        }
654     }
655     nChan = 0;
656 }
657 
658 
659 void SbiIoSystem::Close()
660 {
661     if( !nChan )
662     {
663         nError = ERRCODE_BASIC_BAD_CHANNEL;
664     }
665     else if( !pChan[ nChan ] )
666     {
667         nError = ERRCODE_BASIC_BAD_CHANNEL;
668     }
669     else
670     {
671         nError = pChan[ nChan ]->Close();
672         delete pChan[ nChan ];
673         pChan[ nChan ] = nullptr;
674     }
675     nChan = 0;
676 }
677 
678 
679 void SbiIoSystem::Shutdown()
680 {
681     for( short i = 1; i < CHANNELS; i++ )
682     {
683         if( pChan[ i ] )
684         {
685             ErrCode n = pChan[ i ]->Close();
686             delete pChan[ i ];
687             pChan[ i ] = nullptr;
688             if( n && !nError )
689             {
690                 nError = n;
691             }
692         }
693     }
694     nChan = 0;
695     // anything left to PRINT?
696     if( !aOut.isEmpty() )
697     {
698         vcl::Window* pParent = Application::GetDefDialogParent();
699         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent ? pParent->GetFrameWeld() : nullptr, VclMessageType::Warning,
700             VclButtonsType::Ok, aOut));
701         xBox->run();
702     }
703     aOut.clear();
704 }
705 
706 
707 void SbiIoSystem::Read(OString& rBuf)
708 {
709     if( !nChan )
710     {
711         ReadCon( rBuf );
712     }
713     else if( !pChan[ nChan ] )
714     {
715         nError = ERRCODE_BASIC_BAD_CHANNEL;
716     }
717     else
718     {
719         nError = pChan[ nChan ]->Read( rBuf );
720     }
721 }
722 
723 char SbiIoSystem::Read()
724 {
725     char ch = ' ';
726     if( !nChan )
727     {
728         if( aIn.isEmpty() )
729         {
730             ReadCon( aIn );
731             aIn = aIn + OString('\n');
732         }
733         ch = aIn[0];
734         aIn = aIn.copy(1);
735     }
736     else if( !pChan[ nChan ] )
737     {
738         nError = ERRCODE_BASIC_BAD_CHANNEL;
739     }
740     else
741     {
742         nError = pChan[ nChan ]->Read( ch );
743     }
744     return ch;
745 }
746 
747 void SbiIoSystem::Write(const OUString& rBuf)
748 {
749     if( !nChan )
750     {
751         WriteCon( rBuf );
752     }
753     else if( !pChan[ nChan ] )
754     {
755         nError = ERRCODE_BASIC_BAD_CHANNEL;
756     }
757     else
758     {
759         nError = pChan[ nChan ]->Write( OUStringToOString(rBuf, osl_getThreadTextEncoding()) );
760     }
761 }
762 
763 // nChannel == 0..CHANNELS-1
764 
765 SbiStream* SbiIoSystem::GetStream( short nChannel ) const
766 {
767     SbiStream* pRet = nullptr;
768     if( nChannel >= 0 && nChannel < CHANNELS )
769     {
770         pRet = pChan[ nChannel ];
771     }
772     return pRet;
773 }
774 
775 void SbiIoSystem::CloseAll()
776 {
777     for( short i = 1; i < CHANNELS; i++ )
778     {
779         if( pChan[ i ] )
780         {
781             ErrCode n = pChan[ i ]->Close();
782             delete pChan[ i ];
783             pChan[ i ] = nullptr;
784             if( n && !nError )
785             {
786                 nError = n;
787             }
788         }
789     }
790 }
791 
792 void SbiIoSystem::ReadCon(OString& rIn)
793 {
794     OUString aPromptStr(OStringToOUString(aPrompt, osl_getThreadTextEncoding()));
795     SbiInputDialog aDlg(nullptr, aPromptStr);
796     if (aDlg.run() == RET_OK)
797     {
798         rIn = OUStringToOString(aDlg.GetInput(), osl_getThreadTextEncoding());
799     }
800     else
801     {
802         nError = ERRCODE_BASIC_USER_ABORT;
803     }
804     aPrompt.clear();
805 }
806 
807 // output of a MessageBox, if there's a CR in the console-buffer
808 
809 void SbiIoSystem::WriteCon(const OUString& rText)
810 {
811     aOut += rText;
812     sal_Int32 n1 = aOut.indexOf('\n');
813     sal_Int32 n2 = aOut.indexOf('\r');
814     if( n1 != -1 || n2 != -1 )
815     {
816         if( n1 == -1 )
817         {
818             n1 = n2;
819         }
820         else if( n2 == -1 )
821         {
822             n2 = n1;
823         }
824         if( n1 > n2 )
825         {
826             n1 = n2;
827         }
828         OUString s(aOut.copy(0, n1));
829         aOut = aOut.copy(n1);
830         while ( !aOut.isEmpty() && (aOut[0] == '\n' || aOut[0] == '\r') )
831         {
832             aOut = aOut.copy(1);
833         }
834         {
835             SolarMutexGuard aSolarGuard;
836 
837             vcl::Window* pParent = Application::GetDefDialogParent();
838             std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent ? pParent->GetFrameWeld() : nullptr, VclMessageType::Warning,
839                 VclButtonsType::OkCancel, s));
840             xBox->set_default_response(RET_OK);
841             if (!xBox->run())
842             {
843                 nError = ERRCODE_BASIC_USER_ABORT;
844             }
845         }
846     }
847 }
848 
849 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
850