-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[mono] Implement System.Console for iOS #33827
Changes from 10 commits
b109227
9c8abf7
e9947ad
770e45c
3072234
beca65b
bc91e3d
87e1757
172499c
1ef7abf
770ca45
0dcc8a9
b7c0bcc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Runtime.InteropServices; | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Sys | ||
{ | ||
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Log")] | ||
internal static extern unsafe bool Log(byte* buffer, int count); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
#pragma once | ||
|
||
#include "pal_compiler.h" | ||
#include "pal_types.h" | ||
|
||
PALEXPORT void SystemNative_Log(uint8_t* buffer, int32_t length); | ||
|
||
// Called by pal_signal.cpp to reinitialize the console on SIGCONT/SIGCHLD. | ||
void ReinitializeTerminal(void) {} | ||
void UninitializeTerminal(void) {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
#include "pal_log.h" | ||
#import <Foundation/Foundation.h> | ||
|
||
void SystemNative_Log (uint8_t* buffer, int32_t length) | ||
{ | ||
NSString *msg = [[NSString alloc] initWithBytes: buffer length: length encoding: NSUTF16LittleEndianStringEncoding]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How does error handling work in Objective C? Does this throw exceptions? What is the usual way to deal with it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
if (length > 4096) | ||
{ | ||
// Write in chunks of max 4096 characters; older versions of iOS seems to have a bug where NSLog may hang with long strings (!). | ||
// https://github.com/xamarin/maccore/issues/1014 | ||
const char* utf8 = [msg UTF8String]; | ||
size_t len = strlen (utf8); | ||
const size_t max_size = 4096; | ||
while (len > 0) | ||
{ | ||
size_t chunk_size = len > max_size ? max_size : len; | ||
|
||
// Try to not break in the middle of a line, by looking backwards for a newline | ||
while (chunk_size > 0 && utf8 [chunk_size] != 0 && utf8 [chunk_size] != '\n') | ||
{ | ||
chunk_size--; | ||
} | ||
if (chunk_size == 0) | ||
{ | ||
// No newline found, break in the middle. | ||
chunk_size = len > max_size ? max_size : len; | ||
} | ||
NSLog (@"%.*s", (int) chunk_size, utf8); | ||
len -= chunk_size; | ||
utf8 += chunk_size; | ||
} | ||
} | ||
else | ||
{ | ||
NSLog (@"%@", msg); | ||
} | ||
[msg release]; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.IO; | ||
using System.Text; | ||
|
||
namespace System | ||
{ | ||
internal sealed class NSLogStream : Stream | ||
{ | ||
public override void Flush() { } | ||
|
||
public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException(); | ||
|
||
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); | ||
|
||
public override void SetLength(long value) => throw new NotSupportedException(); | ||
|
||
public override unsafe void Write(byte[] buffer, int offset, int count) | ||
{ | ||
if (count > 0 && count <= buffer.Length - offset) | ||
EgorBo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
fixed (byte* ptr = buffer) | ||
{ | ||
Interop.Sys.Log(ptr + offset, count); | ||
} | ||
} | ||
} | ||
|
||
public override bool CanRead => false; | ||
|
||
public override bool CanSeek => false; | ||
|
||
public override bool CanWrite => true; | ||
|
||
public override long Length => throw new NotSupportedException(); | ||
|
||
public override long Position | ||
{ | ||
get => throw new NotSupportedException(); | ||
set => throw new NotSupportedException(); | ||
} | ||
} | ||
|
||
internal static class ConsolePal | ||
{ | ||
public static Stream OpenStandardInput() => throw new PlatformNotSupportedException(); | ||
|
||
public static Stream OpenStandardOutput() => new NSLogStream(); | ||
|
||
public static Stream OpenStandardError() => new NSLogStream(); | ||
|
||
public static Encoding InputEncoding => throw new PlatformNotSupportedException(); | ||
|
||
public static void SetConsoleInputEncoding(Encoding enc) => throw new PlatformNotSupportedException(); | ||
|
||
public static Encoding OutputEncoding => Encoding.Unicode; | ||
|
||
// underlying API expects only utf-16 | ||
EgorBo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
public static void SetConsoleOutputEncoding(Encoding enc) => throw new PlatformNotSupportedException(); | ||
|
||
public static bool IsInputRedirectedCore() => false; | ||
|
||
public static bool IsOutputRedirectedCore() => false; | ||
|
||
public static bool IsErrorRedirectedCore() => false; | ||
|
||
internal static TextReader GetOrCreateReader() => throw new PlatformNotSupportedException(); | ||
|
||
public static bool NumberLock => false; | ||
|
||
public static bool CapsLock => false; | ||
|
||
public static bool KeyAvailable => false; | ||
|
||
public static ConsoleKeyInfo ReadKey(bool intercept) => throw new PlatformNotSupportedException(); | ||
|
||
public static bool TreatControlCAsInput | ||
{ | ||
get => throw new PlatformNotSupportedException(); | ||
set => throw new PlatformNotSupportedException(); | ||
} | ||
|
||
public static ConsoleColor BackgroundColor | ||
{ | ||
get => throw new PlatformNotSupportedException(); | ||
set => throw new PlatformNotSupportedException(); | ||
} | ||
|
||
public static ConsoleColor ForegroundColor | ||
{ | ||
get => throw new PlatformNotSupportedException(); | ||
set => throw new PlatformNotSupportedException(); | ||
} | ||
|
||
public static void ResetColor() => throw new PlatformNotSupportedException(); | ||
|
||
public static int CursorSize | ||
{ | ||
get => throw new PlatformNotSupportedException(); | ||
set => throw new PlatformNotSupportedException(); | ||
} | ||
|
||
public static bool CursorVisible | ||
{ | ||
get => throw new PlatformNotSupportedException(); | ||
set => throw new PlatformNotSupportedException(); | ||
} | ||
|
||
public static int CursorLeft => throw new PlatformNotSupportedException(); | ||
|
||
public static int CursorTop => throw new PlatformNotSupportedException(); | ||
|
||
public static string Title | ||
{ | ||
get => throw new PlatformNotSupportedException(); | ||
set => throw new PlatformNotSupportedException(); | ||
} | ||
|
||
public static void Beep() => throw new PlatformNotSupportedException(); | ||
|
||
public static void Beep(int frequency, int duration) => throw new PlatformNotSupportedException(); | ||
|
||
public static void MoveBufferArea(int sourceLeft, int sourceTop, | ||
int sourceWidth, int sourceHeight, int targetLeft, int targetTop, | ||
char sourceChar, ConsoleColor sourceForeColor, | ||
ConsoleColor sourceBackColor) => throw new PlatformNotSupportedException(); | ||
|
||
public static void Clear() => throw new PlatformNotSupportedException(); | ||
|
||
public static void SetCursorPosition(int left, int top) => throw new PlatformNotSupportedException(); | ||
|
||
public static int BufferWidth | ||
{ | ||
get => throw new PlatformNotSupportedException(); | ||
set => throw new PlatformNotSupportedException(); | ||
} | ||
|
||
public static int BufferHeight | ||
{ | ||
get => throw new PlatformNotSupportedException(); | ||
set => throw new PlatformNotSupportedException(); | ||
} | ||
|
||
public static void SetBufferSize(int width, int height) => throw new PlatformNotSupportedException(); | ||
|
||
public static int LargestWindowWidth => throw new PlatformNotSupportedException(); | ||
|
||
public static int LargestWindowHeight => throw new PlatformNotSupportedException(); | ||
|
||
public static int WindowLeft | ||
{ | ||
get => throw new PlatformNotSupportedException(); | ||
set => throw new PlatformNotSupportedException(); | ||
} | ||
|
||
public static int WindowTop | ||
{ | ||
get => throw new PlatformNotSupportedException(); | ||
set => throw new PlatformNotSupportedException(); | ||
} | ||
|
||
public static int WindowWidth | ||
{ | ||
get => throw new PlatformNotSupportedException(); | ||
set => throw new PlatformNotSupportedException(); | ||
} | ||
|
||
public static int WindowHeight | ||
{ | ||
get => throw new PlatformNotSupportedException(); | ||
set => throw new PlatformNotSupportedException(); | ||
} | ||
|
||
public static void SetWindowPosition(int left, int top) => throw new PlatformNotSupportedException(); | ||
|
||
public static void SetWindowSize(int width, int height) => throw new PlatformNotSupportedException(); | ||
|
||
internal sealed class ControlCHandlerRegistrar | ||
{ | ||
internal ControlCHandlerRegistrar() => throw new PlatformNotSupportedException(); | ||
|
||
internal void Register() => throw new PlatformNotSupportedException(); | ||
|
||
internal void Unregister() => throw new PlatformNotSupportedException(); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You put this under src/Interop/OSX. Is that correct? Or should there be an iOS-specific folder?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sadly there is no general mac folder where this would be better placed (https://developer.apple.com/documentation/foundation/1395275-nslog) or is the intention to copy the interop to System.Native implementation for all OSes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meaning this API is available on any mac, whether OSX or iOS or watch or whatever? We can certainly create a folder for such APIs, assuming we're also making sure that the export it's targeting from System.Native is built on all such platforms. Or if we're only building in the export for iOS, then an iOS-specific folder would make more sense. Presumably in the fullness of time we'll find some APIs that are specific to iOS and so we'll want an iOS folder anyway?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd move it to iOS honestly (just like in my previous commit) we are not going to use this API on OSX, only iOS/tvOS/watchOS which all are basically the same OS almost 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's possible that we find some API which will be ios only but at the level, we operate it's most likely that PAL for ios, tvos, watchos, catalyst and some parts macOS will be identical
We could use
ios
name for modern apple or whatever is the better name but it might be confusing for the contributorsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd use something generic like
apple
for the pieces that work across mac/ios/tvos/watchos.Doesn't need to be done here though since there are a lot of cases where we'll need to rename the Interop/OSX folder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so are we ok with OSX then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so. It does not make sense to try to redo the directory structure in this PR.