Add ONLCR and OCRNL.

This is a compatible ABI change.
This commit is contained in:
Jonas 'Sortie' Termansen 2016-11-05 15:23:41 +01:00
parent 9603be8e65
commit d720f16537
8 changed files with 148 additions and 17 deletions

View File

@ -157,7 +157,7 @@ sysroot-system: sysroot-fsh sysroot-base-headers
echo 'ID=sortix' && \
echo 'VERSION_ID="$(VERSION)"' && \
echo 'PRETTY_NAME="Sortix $(VERSION)"' && \
echo 'SORTIX_ABI=0.0' && \
echo 'SORTIX_ABI=0.1' && \
true) > "$(SYSROOT)/etc/sortix-release"
echo /etc/sortix-release >> "$(SYSROOT)/tix/manifest/system"
ln -sf sortix-release "$(SYSROOT)/etc/os-release"

View File

@ -45,6 +45,7 @@ extern size_t fallback_framebuffer_height;
extern TextBufferHandle* device_textbufhandle;
extern size_t (*device_callback)(void*, const char*, size_t);
extern size_t (*device_writeraw)(void*, const char*, size_t);
extern size_t (*device_width)(void*);
extern size_t (*device_height)(void*);
extern void (*device_get_cursor)(void*, size_t*, size_t*);
@ -55,6 +56,7 @@ extern bool (*emergency_device_is_impaired)(void*);
extern bool (*emergency_device_recoup)(void*);
extern void (*emergency_device_reset)(void*);
extern size_t (*emergency_device_callback)(void*, const char*, size_t);
extern size_t (*emergency_device_writeraw)(void*, const char*, size_t);
extern size_t (*emergency_device_width)(void*);
extern size_t (*emergency_device_height)(void*);
extern void (*emergency_device_get_cursor)(void*, size_t*, size_t*);
@ -98,7 +100,7 @@ inline size_t Print(const char* str)
inline size_t PrintData(const void* ptr, size_t size)
{
return device_callback(device_pointer, (const char*) ptr, size);
return device_writeraw(device_pointer, (const char*) ptr, size);
}
__attribute__((format(printf, 1, 2)))

View File

@ -50,6 +50,10 @@
#define PARMRK (1U << 11)
#define OPOST (1U << 0)
#if __USE_SORTIX || __USE_XOPEN
#define ONLCR (1U << 1)
#define OCRNL (1U << 2)
#endif
#define B0 0
#define B50 50

View File

@ -29,6 +29,9 @@
#define TERMMODE_NONBLOCK (1U << 6) /* ISORTIX_NONBLOCK */
#define TERMMODE_TERMIOS (1U << 7) /* !ISORTIX_TERMMODE */
#define TERMMODE_DISABLE (1U << 8) /* !CREAD */
#define TERMMODE_NOOPOST (1U << 9) /* !OPOST */
#define TERMMODE_NOONLCR (1U << 10) /* !ONLCR */
#define TERMMODE_OCRNL (1U << 11) /* OCRNL */
#define TERMMODE_NORMAL (TERMMODE_UNICODE | TERMMODE_SIGNAL | TERMMODE_UTF8 | \
TERMMODE_LINEBUFFER | TERMMODE_ECHO | TERMMODE_TERMIOS)

View File

@ -44,6 +44,7 @@ size_t fallback_framebuffer_height = 0;
TextBufferHandle* device_textbufhandle = NULL;
size_t (*device_callback)(void*, const char*, size_t) = NULL;
size_t (*device_writeraw)(void*, const char*, size_t) = NULL;
size_t (*device_width)(void*) = NULL;
size_t (*device_height)(void*) = NULL;
void (*device_get_cursor)(void*, size_t*, size_t*) = NULL;
@ -54,6 +55,7 @@ bool (*emergency_device_is_impaired)(void*) = NULL;
bool (*emergency_device_recoup)(void*) = NULL;
void (*emergency_device_reset)(void*) = NULL;
size_t (*emergency_device_callback)(void*, const char*, size_t) = NULL;
size_t (*emergency_device_writeraw)(void*, const char*, size_t) = NULL;
size_t (*emergency_device_width)(void*) = NULL;
void (*emergency_device_get_cursor)(void*, size_t*, size_t*) = NULL;
size_t (*emergency_device_height)(void*) = NULL;
@ -65,6 +67,11 @@ static size_t PrintToTextTerminal(void* user, const char* str, size_t len)
return ((TextTerminal*) user)->Print(str, len);
}
static size_t PrintRawToTextTerminal(void* user, const char* str, size_t len)
{
return ((TextTerminal*) user)->PrintRaw(str, len);
}
static size_t TextTermWidth(void* user)
{
return ((TextTerminal*) user)->Width();
@ -111,6 +118,12 @@ size_t EmergencyPrintToTextTerminal(void* user, const char* str, size_t len)
return ((TextTerminal*) user)->EmergencyPrint(str, len);
}
static
size_t EmergencyPrintRawToTextTerminal(void* user, const char* str, size_t len)
{
return ((TextTerminal*) user)->EmergencyPrintRaw(str, len);
}
static size_t EmergencyTextTermWidth(void* user)
{
return ((TextTerminal*) user)->EmergencyWidth();
@ -192,6 +205,7 @@ void Init(multiboot_info_t* bootinfo)
// Register the text terminal as the kernel log.
Log::device_callback = PrintToTextTerminal;
Log::device_writeraw = PrintRawToTextTerminal;
Log::device_width = TextTermWidth;
Log::device_height = TextTermHeight;
Log::device_get_cursor = TextTermGetCursor;
@ -204,6 +218,7 @@ void Init(multiboot_info_t* bootinfo)
Log::emergency_device_recoup = EmergencyTextTermRecoup;
Log::emergency_device_reset = EmergencyTextTermReset;
Log::emergency_device_callback = EmergencyPrintToTextTerminal;
Log::emergency_device_writeraw = EmergencyPrintRawToTextTerminal;
Log::emergency_device_width = EmergencyTextTermWidth;
Log::emergency_device_height = EmergencyTextTermHeight;
Log::emergency_device_get_cursor = EmergencyTextTermGetCursor;

View File

@ -63,6 +63,21 @@ void TextTerminal::Reset()
}
size_t TextTerminal::Print(const char* string, size_t stringlen)
{
ScopedLock lock(&termlock);
TextBuffer* textbuf = textbufhandle->Acquire();
for ( size_t i = 0; i < stringlen; i++ )
{
if ( string[i] == '\n' )
PutChar(textbuf, '\r');
PutChar(textbuf, string[i]);
}
UpdateCursor(textbuf);
textbufhandle->Release(textbuf);
return stringlen;
}
size_t TextTerminal::PrintRaw(const char* string, size_t stringlen)
{
ScopedLock lock(&termlock);
TextBuffer* textbuf = textbufhandle->Acquire();
@ -185,6 +200,25 @@ size_t TextTerminal::EmergencyPrint(const char* string, size_t stringlen)
// while it held the terminal lock. The best case is if the terminal lock is
// currently unused, which would mean everything is safe.
TextBuffer* textbuf = textbufhandle->EmergencyAcquire();
for ( size_t i = 0; i < stringlen; i++ )
{
if ( string[i] == '\n' )
PutChar(textbuf, '\r');
PutChar(textbuf, string[i]);
}
UpdateCursor(textbuf);
textbufhandle->EmergencyRelease(textbuf);
return stringlen;
}
size_t TextTerminal::EmergencyPrintRaw(const char* string, size_t stringlen)
{
// This is during a kernel emergency where preemption has been disabled and
// this is the only thread running. Another thread may have been interrupted
// while it held the terminal lock. The best case is if the terminal lock is
// currently unused, which would mean everything is safe.
TextBuffer* textbuf = textbufhandle->EmergencyAcquire();
for ( size_t i = 0; i < stringlen; i++ )
PutChar(textbuf, string[i]);
@ -271,7 +305,10 @@ void TextTerminal::PutChar(TextBuffer* textbuf, char c)
wc = L' ';
if ( textbuf->Width() <= column )
{
column = 0;
Newline(textbuf);
}
TextPos pos(column++, line);
TextChar tc(wc, vgacolor, ATTR_CHAR | next_attr);
textbuf->SetChar(pos, tc);
@ -286,7 +323,6 @@ void TextTerminal::UpdateCursor(TextBuffer* textbuf)
void TextTerminal::Newline(TextBuffer* textbuf)
{
TextPos pos(column, line);
column = 0;
if ( line < textbuf->Height()-1 )
line++;
else
@ -330,7 +366,10 @@ void TextTerminal::Backspace(TextBuffer* textbuf)
void TextTerminal::Tab(TextBuffer* textbuf)
{
if ( column == textbuf->Width() )
{
column = 0;
Newline(textbuf);
}
unsigned int count = 8 - (column % 8);
for ( unsigned int i = 0; i < count; i++ )
{

View File

@ -35,6 +35,7 @@ public:
TextTerminal(TextBufferHandle* textbufhandle);
~TextTerminal();
size_t Print(const char* string, size_t stringlen);
size_t PrintRaw(const char* string, size_t stringlen);
size_t Width() const;
size_t Height() const;
void GetCursor(size_t* column, size_t* row) const;
@ -44,6 +45,7 @@ public:
bool EmergencyRecoup();
void EmergencyReset();
size_t EmergencyPrint(const char* string, size_t stringlen);
size_t EmergencyPrintRaw(const char* string, size_t stringlen);
size_t EmergencyWidth() const;
size_t EmergencyHeight() const;
void EmergencyGetCursor(size_t* column, size_t* row) const;

View File

@ -63,7 +63,10 @@ static const unsigned int SUPPORTED_TERMMODES = TERMMODE_KBKEY
| TERMMODE_ECHO
| TERMMODE_NONBLOCK
| TERMMODE_TERMIOS
| TERMMODE_DISABLE;
| TERMMODE_DISABLE
| TERMMODE_NOOPOST
| TERMMODE_NOONLCR
| TERMMODE_OCRNL;
static inline bool IsByteUnescaped(unsigned char byte)
{
@ -89,7 +92,7 @@ TTY::TTY(dev_t dev, mode_t mode, uid_t owner, gid_t group)
this->stat_gid = group;
memset(&tio, 0, sizeof(tio));
tio.c_iflag = BRKINT | ICRNL | IXANY | IXON;
tio.c_oflag = OPOST;
tio.c_oflag = OPOST | ONLCR;
tio.c_cflag = CS8 /*| CREAD*/ | HUPCL; // CREAD unset for boot security.
tio.c_lflag = ECHO | ECHOE | ECHOK | ICANON | IEXTEN | ISIG;
tio.c_cc[VEOF] = CONTROL('D');
@ -127,6 +130,8 @@ int TTY::settermmode(ioctx_t* /*ctx*/, unsigned int termmode)
tcflag_t new_cflag = old_cflag;
tcflag_t old_lflag = tio.c_lflag;
tcflag_t new_lflag = old_lflag;
tcflag_t old_oflag = tio.c_oflag;
tcflag_t new_oflag = old_oflag;
if ( termmode & TERMMODE_KBKEY )
new_lflag |= ISORTIX_KBKEY;
else
@ -163,12 +168,25 @@ int TTY::settermmode(ioctx_t* /*ctx*/, unsigned int termmode)
new_cflag |= CREAD;
else
new_cflag &= ~CREAD;
if ( !(termmode & TERMMODE_NOOPOST) )
new_oflag |= OPOST;
else
new_oflag &= ~OPOST;
if ( !(termmode & TERMMODE_NOONLCR) )
new_oflag |= ONLCR;
else
new_oflag &= ~ONLCR;
if ( termmode & TERMMODE_OCRNL )
new_oflag |= OCRNL;
else
new_oflag &= ~OCRNL;
bool oldnoutf8 = old_lflag & ISORTIX_32BIT;
bool newnoutf8 = new_lflag & ISORTIX_32BIT;
if ( oldnoutf8 != newnoutf8 )
memset(&read_ps, 0, sizeof(read_ps));
tio.c_cflag = new_cflag;
tio.c_lflag = new_lflag;
tio.c_oflag = new_oflag;
if ( !(tio.c_lflag & ICANON) )
CommitLineBuffer();
return 0;
@ -196,6 +214,12 @@ int TTY::gettermmode(ioctx_t* ctx, unsigned int* mode)
termmode |= TERMMODE_TERMIOS;
if ( !(tio.c_cflag & CREAD) )
termmode |= TERMMODE_DISABLE;
if ( !(tio.c_oflag & OPOST) )
termmode |= TERMMODE_NOOPOST;
if ( !(tio.c_oflag & ONLCR) )
termmode |= TERMMODE_NOONLCR;
if ( tio.c_oflag & OCRNL )
termmode |= TERMMODE_OCRNL;
if ( !ctx->copy_to_dest(mode, &termmode, sizeof(termmode)) )
return -1;
return 0;
@ -418,7 +442,16 @@ void TTY::ProcessByte(unsigned char byte, uint32_t control_unicode)
if ( tio.c_lflag & ECHO )
{
if ( IsByteUnescaped(byte) )
if ( byte == '\n' )
{
if ( tio.c_oflag & OPOST && tio.c_oflag & ONLCR )
Log::PrintData("\r\n", 2);
else if ( tio.c_oflag & OPOST && tio.c_oflag & OCRNL )
Log::PrintData("\r", 1);
else
Log::PrintData("\n", 1);
}
else if ( IsByteUnescaped(byte) )
Log::PrintData(&byte, 1);
else
Log::PrintF("^%c", CONTROL(byte));
@ -556,26 +589,59 @@ ssize_t TTY::write(ioctx_t* ctx, const uint8_t* io_buffer, size_t count)
if ( tio.c_lflag & TOSTOP && !RequireForeground(SIGTTOU) )
return errno = EINTR, -1;
// TODO: Add support for ioctx to the kernel log.
const size_t BUFFER_SIZE = 64UL;
char buffer[BUFFER_SIZE];
unsigned char buffer[256];
size_t max_incoming = sizeof(buffer);
if ( tio.c_oflag & OPOST && tio.c_oflag & ONLCR )
max_incoming = sizeof(buffer) / 2;
size_t sofar = 0;
size_t rounds = 0;
while ( sofar < count )
{
size_t amount = count - sofar;
if ( BUFFER_SIZE < amount )
amount = BUFFER_SIZE;
if ( !ctx->copy_from_src(buffer, io_buffer + sofar, amount) )
size_t incoming = count - sofar;
if ( max_incoming < incoming )
incoming = max_incoming;
if ( !ctx->copy_from_src(buffer, io_buffer + sofar, incoming) )
return -1;
Log::PrintData(buffer, amount);
sofar += amount;
if ( sofar < count )
size_t offset;
size_t outgoing;
if ( tio.c_oflag & OPOST && tio.c_oflag & ONLCR )
{
offset = sizeof(buffer);
outgoing = incoming;
for ( size_t ii = incoming; ii; ii-- )
{
size_t i = ii - 1;
if ( buffer[i] == '\n' )
{
buffer[--offset] = '\n';
buffer[--offset] = '\r';
outgoing++;
}
else
buffer[--offset] = buffer[i];
}
}
else
{
offset = 0;
outgoing = incoming;
if ( tio.c_oflag & OPOST && tio.c_oflag & OCRNL )
{
for ( size_t i = 0; i < incoming; i++ )
if ( buffer[i] == '\r' )
buffer[i] = '\n';
}
}
Log::PrintData(buffer + offset, outgoing);
sofar += incoming;
if ( ++rounds % 16 == 0 )
{
kthread_mutex_unlock(&termlock);
kthread_yield();
kthread_mutex_lock(&termlock);
if ( Signal::IsPending() )
return sofar;
}
if ( Signal::IsPending() )
return sofar;
}
return (ssize_t) sofar;
}