Skip to content

Commit

Permalink
Executable runner
Browse files Browse the repository at this point in the history
  • Loading branch information
NSAntoine committed Sep 6, 2022
1 parent bb0d7db commit cbe002c
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 2 deletions.
16 changes: 16 additions & 0 deletions Santander.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
37EEA03928A8C86B00FA8CEB /* unzip.c in Sources */ = {isa = PBXBuildFile; fileRef = 37EEA02F28A8C86A00FA8CEB /* unzip.c */; };
37EEA03A28A8C86B00FA8CEB /* ioapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 37EEA03728A8C86B00FA8CEB /* ioapi.c */; };
37EEA03B28A8C86B00FA8CEB /* zip.c in Sources */ = {isa = PBXBuildFile; fileRef = 37EEA03828A8C86B00FA8CEB /* zip.c */; };
CE5DFE8328C7BC89003E1095 /* BinaryExecutionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE5DFE8228C7BC89003E1095 /* BinaryExecutionViewController.swift */; };
CECF6EDA28C37F660080B805 /* FontViewerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CECF6ED928C37F660080B805 /* FontViewerController.swift */; };
CEDAF42028C36B2900DF03E6 /* Runestone in Frameworks */ = {isa = PBXBuildFile; productRef = CEDAF41F28C36B2900DF03E6 /* Runestone */; };
CEF54FF528C3D4E30078A146 /* FontInformationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEF54FF428C3D4E30078A146 /* FontInformationViewController.swift */; };
Expand Down Expand Up @@ -131,8 +132,11 @@
37EEA03528A8C86A00FA8CEB /* ioapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ioapi.h; sourceTree = "<group>"; };
37EEA03728A8C86B00FA8CEB /* ioapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ioapi.c; sourceTree = "<group>"; };
37EEA03828A8C86B00FA8CEB /* zip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip.c; sourceTree = "<group>"; };
CE5DFE8228C7BC89003E1095 /* BinaryExecutionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinaryExecutionViewController.swift; sourceTree = "<group>"; };
CECF6ED928C37F660080B805 /* FontViewerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontViewerController.swift; sourceTree = "<group>"; };
CEF54FF428C3D4E30078A146 /* FontInformationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontInformationViewController.swift; sourceTree = "<group>"; };
CEFA0D7928C7CCAA003A0764 /* NSTask.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSTask.h; sourceTree = "<group>"; };
CEFA0D7A28C7CCE1003A0764 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -273,6 +277,7 @@
37934DB528707F3200D1248A /* Editors */ = {
isa = PBXGroup;
children = (
CE5DFE8228C7BC89003E1095 /* BinaryExecutionViewController.swift */,
3758315C28B4D2E9001E63F2 /* TextEditor */,
376F749E28BC8A4F000E5D77 /* Audio */,
3787DB0828ACE4C900ACA60B /* Serialized */,
Expand Down Expand Up @@ -311,6 +316,7 @@
37EEA02428A8BE4E00FA8CEB /* External */ = {
isa = PBXGroup;
children = (
CEFA0D7828C7CC5B003A0764 /* NSTask */,
372A570928AA436400781243 /* LaunchServices */,
37EEA03C28A912B900FA8CEB /* Compression */,
);
Expand Down Expand Up @@ -358,6 +364,15 @@
path = Font;
sourceTree = "<group>";
};
CEFA0D7828C7CC5B003A0764 /* NSTask */ = {
isa = PBXGroup;
children = (
CEFA0D7928C7CCAA003A0764 /* NSTask.h */,
CEFA0D7A28C7CCE1003A0764 /* module.modulemap */,
);
path = NSTask;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -464,6 +479,7 @@
37DE0FA22864902400E5EBBC /* FilePreviewDataSource.swift in Sources */,
37963F17286A0F0B00C4B72A /* DirectoryMonitor.swift in Sources */,
37EEA02828A8BF2700FA8CEB /* Compression.swift in Sources */,
CE5DFE8328C7BC89003E1095 /* BinaryExecutionViewController.swift in Sources */,
37EEA03B28A8C86B00FA8CEB /* zip.c in Sources */,
CEF54FF528C3D4E30078A146 /* FontInformationViewController.swift in Sources */,
375CF897289C394E00BB7C60 /* ToolbarItems.swift in Sources */,
Expand Down
55 changes: 55 additions & 0 deletions Santander/Other/External/NSTask/NSTask.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// NSTask.h
// Santander
//
// Created by Serena on 06/09/2022
//


#ifndef NSTask_h
#define NSTask_h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSTask : NSObject

@property (copy) NSArray <NSString *> *arguments;
@property (copy) NSURL *currentDirectoryURL;
@property (copy) NSDictionary *environment;
@property (copy) NSURL *executableURL;
@property (readonly) int processIdentifier;
@property NSInteger qualityOfService;
@property (getter=isRunning, readonly) BOOL running;
@property (retain) NSPipe *standardError;
@property (retain) id standardInput;
@property (retain) NSPipe *standardOutput;
@property(copy) void (^terminationHandler)(NSTask *);
@property (readonly) NSInteger terminationReason;
@property (readonly) int terminationStatus;


+(id)allocWithZone:(struct _NSZone *)arg0 ;
+(id)currentTaskDictionary;
+(id)launchedTaskWithDictionary:(id)arg0 ;
-(BOOL)isSpawnedProcessDisclaimed;
-(BOOL)resume;
-(BOOL)suspend;
-(NSInteger)suspendCount;
-(BOOL)launchAndReturnError:(out NSError * _Nullable *)error;
-(id)currentDirectoryPath;
-(id)init;
-(id)launchPath;
-(void)waitUntilExit;
-(void)interrupt;
-(void)launch;
-(void)setCurrentDirectoryPath:(id)arg0 ;
-(void)setLaunchPath:(id)arg0 ;
-(void)setSpawnedProcessDisclaimed:(BOOL)arg0 ;
-(void)terminate;

@end
NS_ASSUME_NONNULL_END

#endif /* NSTask_h */
3 changes: 3 additions & 0 deletions Santander/Other/External/NSTask/module.modulemap
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module NSTaskiOS {
header "NSTask.h"
}
133 changes: 133 additions & 0 deletions Santander/UI/Editors/BinaryExecutionViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//
// BinaryExecutionViewController.swift
// Santander
//
// Created by Serena on 06/09/2022
//


import UIKit
import NSTaskiOS

class BinaryExecutionViewController: UIViewController {
let executableURL: URL
var task: NSTask = NSTask()
var textView: UITextView!

init(executableURL: URL) {
self.executableURL = executableURL

super.init(nibName: nil, bundle: nil)
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
super.viewDidLoad()

view.backgroundColor = .secondarySystemBackground

title = "Execution"
let doneAction = UIAction {
if self.task.isRunning {
self.task.interrupt()
}
self.dismiss(animated: true)
}

navigationItem.rightBarButtonItem = UIBarButtonItem(systemItem: .done, primaryAction: doneAction)
configureNavigationBarToNormal()

let executableTextField = UITextField()

let action = UIAction {
if self.task.isRunning {
self.task.interrupt()
}
self.spawnExecutable(pathAndArgs: executableTextField.text!)
}

executableTextField.returnKeyType = .go
executableTextField.addAction(action, for: .primaryActionTriggered)
executableTextField.text = executableURL.path
executableTextField.font = UIFont(name: "Menlo", size: UIFont.systemFontSize)
executableTextField.translatesAutoresizingMaskIntoConstraints = false
executableTextField.backgroundColor = .systemBackground
executableTextField.inputAccessoryView = makeKeyboardToolbar(forTextField: executableTextField)
view.addSubview(executableTextField)

let guide = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
executableTextField.trailingAnchor.constraint(equalTo: guide.trailingAnchor),
executableTextField.leadingAnchor.constraint(equalTo: guide.leadingAnchor),
executableTextField.topAnchor.constraint(equalTo: guide.topAnchor),
executableTextField.heightAnchor.constraint(equalToConstant: 50),
])

self.textView = UITextView()
textView.text = ""
textView.font = .systemFont(ofSize: 20)
textView.isEditable = false
textView.translatesAutoresizingMaskIntoConstraints = false
textView.backgroundColor = view.backgroundColor
view.addSubview(textView)

NSLayoutConstraint.activate([
textView.leadingAnchor.constraint(equalTo: guide.leadingAnchor),
textView.trailingAnchor.constraint(equalTo: guide.trailingAnchor),
textView.topAnchor.constraint(equalTo: executableTextField.bottomAnchor),
textView.heightAnchor.constraint(equalTo: view.heightAnchor)
])
}

func makeKeyboardToolbar(forTextField textField: UITextField) -> UIToolbar {
let toolbar = UIToolbar()

let dismissKeyboardAction = UIAction {
textField.resignFirstResponder()
}

let dismissButton = UIBarButtonItem(title: "Dismiss", primaryAction: dismissKeyboardAction)
toolbar.setItems([.flexibleSpace(), dismissButton], animated: true)
toolbar.sizeToFit()
return toolbar
}

func spawnExecutable(pathAndArgs: String) {
var components = pathAndArgs.components(separatedBy: " ")
guard let executable = components.first, !executable.isEmpty else {
self.errorAlert("Enter a valid executable and arguments.", title: "Input is empty")
return
}

// make it just args
components.removeFirst()
self.task = NSTask()
task.executableURL = URL(fileURLWithPath: executable)
task.arguments = components

let pipe = Pipe()
pipe.fileHandleForReading.readabilityHandler = { outPipe in
guard let output = String(data: outPipe.availableData, encoding: .utf8),
!output.isEmpty else {
return
}

DispatchQueue.main.async {
self.textView.text.append(output)
}
}

task.standardError = pipe
task.standardOutput = pipe
do {
textView.text = ""
try task.launchAndReturnError()
task.waitUntilExit()
} catch {
self.errorAlert(error, title: "Unable to launch process")
}
}
}
12 changes: 10 additions & 2 deletions Santander/UI/Editors/FileEditorType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ struct FileEditor {
}

let type = url.contentType
if type == .unixExecutable {
return FileEditor(type: .executable, viewController: BinaryExecutionViewController(executableURL: url))
}

if type?.isOfType(.audio) ?? false, let audio = FileEditorType.audio.viewController(forPath: url, data: data) {
return FileEditor(type: .audio, viewController: audio)
}
Expand Down Expand Up @@ -81,7 +85,7 @@ struct FileEditor {
}

enum FileEditorType: CustomStringConvertible, CaseIterable {
case audio, image, video, propertyList, json, text, font
case audio, image, video, propertyList, json, text, font, executable

/// Returns the view controller to be used for the file editor type
/// the Data parameter is used so that, when looping over all editor types,
Expand Down Expand Up @@ -139,6 +143,8 @@ enum FileEditorType: CustomStringConvertible, CaseIterable {
}

return FontViewerController(selectedFont: descriptors.first!.uiFont, descriptors: descriptors)
case .executable:
return BinaryExecutionViewController(executableURL: path)
}
}

Expand All @@ -158,12 +164,14 @@ enum FileEditorType: CustomStringConvertible, CaseIterable {
return "Font Viewer"
case .text:
return "Text Editor"
case .executable:
return "Executable Runner"
}
}

var presentAsFullScreen: Bool {
switch self {
case .text, .image, .video:
case .text, .image, .video, .executable:
return true
case .propertyList, .audio, .json, .font:
return false
Expand Down

0 comments on commit cbe002c

Please sign in to comment.