return 0;
}
-#define pakfire_log_file_process_line(file, line, buffer) \
- __pakfire_log_file_process_line(file, line, sizeof(line), buffer)
-
-static int __pakfire_log_file_process_line(struct pakfire_log_file* self,
- char* line, ssize_t length, const char* p) {
- char* e = NULL;
- int num;
-
- // The cursor position
- int cursor = 0;
-
- while (*p) {
- // Match the beginning of an ESC sequence
- switch (*p) {
- case '\x1B':
- p++;
-
- // Match CSI sequences
- switch (*p) {
- case '[':
- p++;
-
- // Parse the number
- num = strtoul(p, &e, 10);
-
- // Continue from after the number
- p = e;
-
- switch (*p) {
- // Move the cursor to the left
- case 'D':
- cursor -= (num > 0) ? num : 1;
-
- // Don't go too far left
- if (cursor < 0)
- cursor = 0;
- break;
-
- // Move the cursor to the right
- case 'C':
- cursor += (num > 0) ? num : 1;
-
- // Don't go too far right
- if (cursor >= length)
- cursor = length - 1;
- break;
-
- // Move to a certain column
- case 'G':
- cursor = (num > 0) ? num - 1 : 0;
-
- // Don't go too far right
- if (cursor >= length)
- cursor = length - 1;
- break;
- }
-
- // Skip the final character
- p++;
- break;
- }
- break;
-
- // Backspace
- case '\x08':
- if (cursor > 0) {
- cursor--;
-
- // Erase the previous character
- line[cursor] = ' ';
- }
- p++;
- break;
-
- // Carriage Return
- case '\x0d':
- // Erase everything up to the cursor
- for (int i = 0; i < cursor; i++)
- line[i] = '\0';
-
- cursor = 0;
- p++;
- break;
-
- // Normal characters
- default:
- if (cursor < length - 1)
- line[cursor++] = *p;
- p++;
- break;
- }
- }
-
- return 0;
-}
-
int pakfire_log_file_write(struct pakfire_log_file* self, const char* buffer, ssize_t length) {
- char line[MAX_LINE_LENGTH] = {};
int r;
// Check inputs
if (unlikely(!self->f))
return -EBADF;
- // Process any ANSI Escape codes
- r = pakfire_log_file_process_line(self, line, buffer);
- if (r < 0)
- return r;
+ // Automatically determine the length
+ if (unlikely(length < 0))
+ length = strlen(buffer);
// Write the buffer to the file
- r = fprintf(self->f, "%s", line);
- if (unlikely(r < 0)) {
+ r = fwrite(buffer, 1, length, self->f);
+ if (unlikely(r < length)) {
ERROR(self->ctx, "Could not write to log file: %m\n");
return -errno;
}
#include <pakfire/string.h>
#include <pakfire/util.h>
+#define MAX_LINE_LENGTH 4096
+
struct pakfire_pty_stdio {
// File Descriptor
int fd;
unsigned close_fd:1;
// Buffer
- char buffer[4096];
+ char buffer[MAX_LINE_LENGTH];
size_t buffered;
// Terminal Attributes
return bytes_read;
}
+#define pakfire_pty_sanitize_line(pty, line, buffer, buffer_length) \
+ __pakfire_pty_sanitize_line(pty, line, sizeof(line), buffer, buffer_length)
+
+static int __pakfire_pty_sanitize_line(struct pakfire_pty* self,
+ char* line, ssize_t line_length, const char* buffer, ssize_t length) {
+ ssize_t i = 0;
+ int num;
+
+ // The cursor position
+ int cursor = 0;
+
+ while (i < length) {
+ switch (buffer[i]) {
+ // Escape
+ case '\x1b':
+ // Skip the escape character
+ i++;
+
+ // CSI
+ if (i < length && buffer[i] == '[') {
+ i++;
+
+ // Reset number
+ num = 0;
+
+ // Parse the number
+ while (i < length) {
+ // Skip any ';'
+ if (buffer[i] == ';') {
+ i++;
+ continue;
+
+ // Parse any digits
+ } else if (isdigit(buffer[i])) {
+ num = num * 10 + (buffer[i] - '0');
+ i++;
+ continue;
+ }
+
+ // Break on all other characters
+ break;
+ }
+
+ // Parse the command
+ if (i < length) {
+ char command = buffer[i++];
+
+ switch (command) {
+ // Move the cursor to the left
+ case 'D':
+ cursor -= (num > 0) ? num : 1;
+
+ // Don't go too far left
+ if (cursor < 0)
+ cursor = 0;
+ break;
+
+ // Move the cursor to the right
+ case 'C':
+ cursor += (num > 0) ? num : 1;
+
+ // Don't go too far right
+ if (cursor >= length)
+ cursor = length - 1;
+ break;
+
+ // Move to a certain column
+ case 'G':
+ cursor = (num > 0) ? num - 1 : 0;
+
+ // Don't go too far right
+ if (cursor >= length)
+ cursor = length - 1;
+ break;
+
+ // Ignore any other sequences
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+ // Backspace
+ case '\x08':
+ if (cursor > 0) {
+ cursor--;
+
+ // Erase the previous character
+ line[cursor] = ' ';
+ }
+ i++;
+ break;
+
+ // Carriage Return
+ case '\x0d':
+ // Erase everything up to the cursor
+ memset(line, '\0', cursor);
+
+ cursor = 0;
+ i++;
+ break;
+
+ // Normal characters
+ default:
+ if (cursor < line_length - 1)
+ line[cursor++] = buffer[i];
+ i++;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t pakfire_pty_send_line(struct pakfire_pty* self,
+ struct pakfire_pty_stdio* stdio, const char* buffer, ssize_t length) {
+ char line[MAX_LINE_LENGTH] = {};
+ int r;
+
+ // Sanitize the line
+ r = pakfire_pty_sanitize_line(self, line, buffer, length);
+ if (r < 0)
+ return r;
+
+ // Call the callback
+ r = stdio->callbacks.stdout_callback(self->ctx,
+ stdio->callbacks.data, line, strlen(line));
+ if (r < 0)
+ return r;
+
+ // We have consumed the entire line
+ return length;
+}
+
/*
Writes as much data as possible from the buffer
*/
eol = stdio->buffer + stdio->buffered - 1;
}
- // Call the callback
- bytes_written = stdio->callbacks.stdout_callback(
- pty->ctx, stdio->callbacks.data, stdio->buffer, eol - stdio->buffer + 1);
+ // Send the line
+ bytes_written = pakfire_pty_send_line(pty, stdio, stdio->buffer, eol - stdio->buffer + 1);
// Abort on error
if (bytes_written < 0)