<commit_before>#include "vterm_internal.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

/*****************
 * API functions *
 *****************/

static void *default_malloc(size_t size, void *allocdata)
{
  void *ptr = malloc(size);
  if(ptr)
    memset(ptr, 0, size);
  return ptr;
}

static void default_free(void *ptr, void *allocdata)
{
  free(ptr);
}

static VTermAllocatorFunctions default_allocator = {
  .malloc = &default_malloc,
  .free   = &default_free,
};

VTerm *vterm_new(int rows, int cols)
{
  return vterm_new_with_allocator(rows, cols, &default_allocator, NULL);
}

VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata)
{
  /* Need to bootstrap using the allocator function directly */
  VTerm *vt = (*funcs->malloc)(sizeof(VTerm), allocdata);

  vt->allocator = funcs;
  vt->allocdata = allocdata;

  vt->rows = rows;
  vt->cols = cols;

  vt->parser.state = NORMAL;

  vt->parser.callbacks = NULL;
  vt->parser.cbdata    = NULL;

  vt->parser.strbuffer_len = 64;
  vt->parser.strbuffer_cur = 0;
  vt->parser.strbuffer = vterm_allocator_malloc(vt, vt->parser.strbuffer_len);

  vt->outbuffer_len = 64;
  vt->outbuffer_cur = 0;
  vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len);

  vt->tmpbuffer_len = 64;
  vt->tmpbuffer = vterm_allocator_malloc(vt, vt->tmpbuffer_len);

  return vt;
}

void vterm_free(VTerm *vt)
{
  if(vt->screen)
    vterm_screen_free(vt->screen);

  if(vt->state)
    vterm_state_free(vt->state);

  vterm_allocator_free(vt, vt->parser.strbuffer);
  vterm_allocator_free(vt, vt->outbuffer);

  vterm_allocator_free(vt, vt);
}

INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size)
{
  return (*vt->allocator->malloc)(size, vt->allocdata);
}

INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr)
{
  (*vt->allocator->free)(ptr, vt->allocdata);
}

void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp)
{
  if(rowsp)
    *rowsp = vt->rows;
  if(colsp)
    *colsp = vt->cols;
}

void vterm_set_size(VTerm *vt, int rows, int cols)
{
  vt->rows = rows;
  vt->cols = cols;

  if(vt->parser.callbacks && vt->parser.callbacks->resize)
    (*vt->parser.callbacks->resize)(rows, cols, vt->parser.cbdata);
}

int vterm_get_utf8(const VTerm *vt)
{
  return vt->mode.utf8;
}

void vterm_set_utf8(VTerm *vt, int is_utf8)
{
  vt->mode.utf8 = is_utf8;
}

INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len)
{
  if(len > vt->outbuffer_len - vt->outbuffer_cur)
    return;

  memcpy(vt->outbuffer + vt->outbuffer_cur, bytes, len);
  vt->outbuffer_cur += len;
}

INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args)
{
  size_t len = vsnprintf(vt->tmpbuffer, vt->tmpbuffer_len,
      format, args);

  vterm_push_output_bytes(vt, vt->tmpbuffer, len);
}

INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...)
{
  va_list args;
  va_start(args, format);
  vterm_push_output_vsprintf(vt, format, args);
  va_end(args);
}

INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...)
{
  size_t cur;

  if(ctrl >= 0x80 && !vt->mode.ctrl8bit)
    cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len,
        ESC_S "%c", ctrl - 0x40);
  else
    cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len,
        "%c", ctrl);

  if(cur >= vt->tmpbuffer_len)
    return;

  va_list args;
  va_start(args, fmt);
  cur += vsnprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
      fmt, args);
  va_end(args);

  if(cur >= vt->tmpbuffer_len)
    return;

  vterm_push_output_bytes(vt, vt->tmpbuffer, cur);
}

INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...)
{
  size_t cur;

  if(!vt->mode.ctrl8bit)
    cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len,
        ESC_S "%c", C1_DCS - 0x40);
  else
    cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len,
        "%c", C1_DCS);

  if(cur >= vt->tmpbuffer_len)
    return;

  va_list args;
  va_start(args, fmt);
  cur += vsnprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
      fmt, args);
  va_end(args);

  if(cur >= vt->tmpbuffer_len)
    return;

  if(!vt->mode.ctrl8bit)
    cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
        ESC_S "%c", C1_ST - 0x40);
  else
    cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
        "%c", C1_ST);
<commit_msg>More efficient one-line implementation of DCS and ST rendering parts of _output_sprintf_dcs<commit_after>#include "vterm_internal.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

/*****************
 * API functions *
 *****************/

static void *default_malloc(size_t size, void *allocdata)
{
  void *ptr = malloc(size);
  if(ptr)
    memset(ptr, 0, size);
  return ptr;
}

static void default_free(void *ptr, void *allocdata)
{
  free(ptr);
}

static VTermAllocatorFunctions default_allocator = {
  .malloc = &default_malloc,
  .free   = &default_free,
};

VTerm *vterm_new(int rows, int cols)
{
  return vterm_new_with_allocator(rows, cols, &default_allocator, NULL);
}

VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata)
{
  /* Need to bootstrap using the allocator function directly */
  VTerm *vt = (*funcs->malloc)(sizeof(VTerm), allocdata);

  vt->allocator = funcs;
  vt->allocdata = allocdata;

  vt->rows = rows;
  vt->cols = cols;

  vt->parser.state = NORMAL;

  vt->parser.callbacks = NULL;
  vt->parser.cbdata    = NULL;

  vt->parser.strbuffer_len = 64;
  vt->parser.strbuffer_cur = 0;
  vt->parser.strbuffer = vterm_allocator_malloc(vt, vt->parser.strbuffer_len);

  vt->outbuffer_len = 64;
  vt->outbuffer_cur = 0;
  vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len);

  vt->tmpbuffer_len = 64;
  vt->tmpbuffer = vterm_allocator_malloc(vt, vt->tmpbuffer_len);

  return vt;
}

void vterm_free(VTerm *vt)
{
  if(vt->screen)
    vterm_screen_free(vt->screen);

  if(vt->state)
    vterm_state_free(vt->state);

  vterm_allocator_free(vt, vt->parser.strbuffer);
  vterm_allocator_free(vt, vt->outbuffer);

  vterm_allocator_free(vt, vt);
}

INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size)
{
  return (*vt->allocator->malloc)(size, vt->allocdata);
}

INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr)
{
  (*vt->allocator->free)(ptr, vt->allocdata);
}

void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp)
{
  if(rowsp)
    *rowsp = vt->rows;
  if(colsp)
    *colsp = vt->cols;
}

void vterm_set_size(VTerm *vt, int rows, int cols)
{
  vt->rows = rows;
  vt->cols = cols;

  if(vt->parser.callbacks && vt->parser.callbacks->resize)
    (*vt->parser.callbacks->resize)(rows, cols, vt->parser.cbdata);
}

int vterm_get_utf8(const VTerm *vt)
{
  return vt->mode.utf8;
}

void vterm_set_utf8(VTerm *vt, int is_utf8)
{
  vt->mode.utf8 = is_utf8;
}

INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len)
{
  if(len > vt->outbuffer_len - vt->outbuffer_cur)
    return;

  memcpy(vt->outbuffer + vt->outbuffer_cur, bytes, len);
  vt->outbuffer_cur += len;
}

INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args)
{
  size_t len = vsnprintf(vt->tmpbuffer, vt->tmpbuffer_len,
      format, args);

  vterm_push_output_bytes(vt, vt->tmpbuffer, len);
}

INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...)
{
  va_list args;
  va_start(args, format);
  vterm_push_output_vsprintf(vt, format, args);
  va_end(args);
}

INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...)
{
  size_t cur;

  if(ctrl >= 0x80 && !vt->mode.ctrl8bit)
    cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len,
        ESC_S "%c", ctrl - 0x40);
  else
    cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len,
        "%c", ctrl);

  if(cur >= vt->tmpbuffer_len)
    return;

  va_list args;
  va_start(args, fmt);
  cur += vsnprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
      fmt, args);
  va_end(args);

  if(cur >= vt->tmpbuffer_len)
    return;

  vterm_push_output_bytes(vt, vt->tmpbuffer, cur);
}

INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...)
{
  size_t cur = 0;

  cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
      vt->mode.ctrl8bit ? "\x90" : ESC_S "P"); // DCS

  if(cur >= vt->tmpbuffer_len)
    return;

  va_list args;
  va_start(args, fmt);
  cur += vsnprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
      fmt, args);
  va_end(args);

  if(cur >= vt->tmpbuffer_len)
    return;

  cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
      vt->mode.ctrl8bit ? "\x9C" : ESC_S "\\"); // ST

{'fraction_non_alphanumeric': 0.15662373505059798, 'fraction_numerical': 0.007129714811407544, 'mean_word_length': 4.0359004053271565, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 169, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5341043', 'n_tokens_mistral': 3567, 'n_tokens_neox': 3446, 'n_words': 679}