#include <pakfire/util.h>
#include <pakfire/xfopen.h>
+#define MAX_LINE_LENGTH 4096
+
struct pakfire_log_file {
struct pakfire_ctx* ctx;
int nrefs;
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;
- // Automatically determine the length
- if (unlikely(length < 0))
- length = strlen(buffer);
+ // Process any ANSI Escape codes
+ r = pakfire_log_file_process_line(self, line, buffer);
+ if (r < 0)
+ return r;
// Write the buffer to the file
- r = fwrite(buffer, 1, length, self->f);
- if (unlikely(r < length)) {
+ r = fprintf(self->f, "%s", line);
+ if (unlikely(r < 0)) {
ERROR(self->ctx, "Could not write to log file: %m\n");
return -errno;
}