view third_party/luajit/src/lib_buffer.c @ 279:b3b547563ec7

Add Google connector service and agent wiki Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code. Co-authored-by: Copilot <[email protected]> Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
author MrJuneJune <me@mrjunejune.com>
date Mon, 17 Aug 2026 22:22:36 -0700
parents 94705b5986b3
children
line wrap: on
line source

/*
** Buffer library.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/

#define lib_buffer_c
#define LUA_LIB

#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"

#include "lj_obj.h"

#if LJ_HASBUFFER
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_buf.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_udata.h"
#include "lj_meta.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#include "lj_cdata.h"
#include "lj_cconv.h"
#endif
#include "lj_strfmt.h"
#include "lj_serialize.h"
#include "lj_lib.h"

/* -- Helper functions ---------------------------------------------------- */

/* Check that the first argument is a string buffer. */
static SBufExt *buffer_tobuf(lua_State *L)
{
  if (!(L->base < L->top && tvisbuf(L->base)))
    lj_err_argtype(L, 1, "buffer");
  return bufV(L->base);
}

/* Ditto, but for writers. */
static LJ_AINLINE SBufExt *buffer_tobufw(lua_State *L)
{
  SBufExt *sbx = buffer_tobuf(L);
  setsbufXL_(sbx, L);
  return sbx;
}

#define buffer_toudata(sbx)	((GCudata *)(sbx)-1)

/* -- Buffer methods ------------------------------------------------------ */

#define LJLIB_MODULE_buffer_method

LJLIB_CF(buffer_method_free)
{
  SBufExt *sbx = buffer_tobuf(L);
  lj_bufx_free(L, sbx);
  L->top = L->base+1;  /* Chain buffer object. */
  return 1;
}

LJLIB_CF(buffer_method_reset)		LJLIB_REC(.)
{
  SBufExt *sbx = buffer_tobuf(L);
  lj_bufx_reset(sbx);
  L->top = L->base+1;  /* Chain buffer object. */
  return 1;
}

LJLIB_CF(buffer_method_skip)		LJLIB_REC(.)
{
  SBufExt *sbx = buffer_tobuf(L);
  MSize n = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
  MSize len = sbufxlen(sbx);
  if (n < len) {
    sbx->r += n;
  } else if (sbufiscow(sbx)) {
    sbx->r = sbx->w;
  } else {
    sbx->r = sbx->w = sbx->b;
  }
  L->top = L->base+1;  /* Chain buffer object. */
  return 1;
}

LJLIB_CF(buffer_method_set)		LJLIB_REC(.)
{
  SBufExt *sbx = buffer_tobuf(L);
  GCobj *ref;
  const char *p;
  MSize len;
#if LJ_HASFFI
  if (tviscdata(L->base+1)) {
    CTState *cts = ctype_cts(L);
    lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
		   L->base+1, CCF_ARG(2));
    len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
  } else
#endif
  {
    GCstr *str = lj_lib_checkstrx(L, 2);
    p = strdata(str);
    len = str->len;
  }
  lj_bufx_free(L, sbx);
  lj_bufx_set_cow(L, sbx, p, len);
  ref = gcV(L->base+1);
  setgcref(sbx->cowref, ref);
  lj_gc_objbarrier(L, buffer_toudata(sbx), ref);
  L->top = L->base+1;  /* Chain buffer object. */
  return 1;
}

LJLIB_CF(buffer_method_put)		LJLIB_REC(.)
{
  SBufExt *sbx = buffer_tobufw(L);
  ptrdiff_t arg, narg = L->top - L->base;
  for (arg = 1; arg < narg; arg++) {
    cTValue *o = &L->base[arg], *mo = NULL;
  retry:
    if (tvisstr(o)) {
      lj_buf_putstr((SBuf *)sbx, strV(o));
    } else if (tvisint(o)) {
      lj_strfmt_putint((SBuf *)sbx, intV(o));
    } else if (tvisnum(o)) {
      lj_strfmt_putfnum((SBuf *)sbx, STRFMT_G14, numV(o));
    } else if (tvisbuf(o)) {
      SBufExt *sbx2 = bufV(o);
      if (sbx2 == sbx) lj_err_arg(L, (int)(arg+1), LJ_ERR_BUFFER_SELF);
      lj_buf_putmem((SBuf *)sbx, sbx2->r, sbufxlen(sbx2));
    } else if (!mo && !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
      /* Call __tostring metamethod inline. */
      copyTV(L, L->top++, mo);
      copyTV(L, L->top++, o);
      lua_call(L, 1, 1);
      o = &L->base[arg];  /* The stack may have been reallocated. */
      copyTV(L, &L->base[arg], L->top-1);
      L->top = L->base + narg;
      goto retry;  /* Retry with the result. */
    } else {
      lj_err_argtype(L, (int)(arg+1), "string/number/__tostring");
    }
    /* Probably not useful to inline other __tostring MMs, e.g. FFI numbers. */
  }
  L->top = L->base+1;  /* Chain buffer object. */
  lj_gc_check(L);
  return 1;
}

LJLIB_CF(buffer_method_putf)		LJLIB_REC(.)
{
  SBufExt *sbx = buffer_tobufw(L);
  lj_strfmt_putarg(L, (SBuf *)sbx, 2, 2);
  L->top = L->base+1;  /* Chain buffer object. */
  lj_gc_check(L);
  return 1;
}

LJLIB_CF(buffer_method_get)		LJLIB_REC(.)
{
  SBufExt *sbx = buffer_tobuf(L);
  ptrdiff_t arg, narg = L->top - L->base;
  if (narg == 1) {
    narg++;
    setnilV(L->top++);  /* get() is the same as get(nil). */
  }
  for (arg = 1; arg < narg; arg++) {
    TValue *o = &L->base[arg];
    MSize n = tvisnil(o) ? LJ_MAX_BUF :
	      (MSize) lj_lib_checkintrange(L, (int)(arg+1), 0, LJ_MAX_BUF);
    MSize len = sbufxlen(sbx);
    if (n > len) n = len;
    setstrV(L, o, lj_str_new(L, sbx->r, n));
    sbx->r += n;
  }
  if (sbx->r == sbx->w && !sbufiscow(sbx)) sbx->r = sbx->w = sbx->b;
  lj_gc_check(L);
  return (int)(narg-1);
}

#if LJ_HASFFI
LJLIB_CF(buffer_method_putcdata)	LJLIB_REC(.)
{
  SBufExt *sbx = buffer_tobufw(L);
  const char *p;
  MSize len;
  if (tviscdata(L->base+1)) {
    CTState *cts = ctype_cts(L);
    lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
		   L->base+1, CCF_ARG(2));
  } else {
    lj_err_argtype(L, 2, "cdata");
  }
  len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
  lj_buf_putmem((SBuf *)sbx, p, len);
  L->top = L->base+1;  /* Chain buffer object. */
  return 1;
}

LJLIB_CF(buffer_method_reserve)		LJLIB_REC(.)
{
  SBufExt *sbx = buffer_tobufw(L);
  MSize sz = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
  GCcdata *cd;
  lj_buf_more((SBuf *)sbx, sz);
  ctype_loadffi(L);
  cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
  *(void **)cdataptr(cd) = sbx->w;
  setcdataV(L, L->top++, cd);
  setintV(L->top++, sbufleft(sbx));
  return 2;
}

LJLIB_CF(buffer_method_commit)		LJLIB_REC(.)
{
  SBufExt *sbx = buffer_tobuf(L);
  MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
  if (len > sbufleft(sbx)) lj_err_arg(L, 2, LJ_ERR_NUMRNG);
  sbx->w += len;
  L->top = L->base+1;  /* Chain buffer object. */
  return 1;
}

LJLIB_CF(buffer_method_ref)		LJLIB_REC(.)
{
  SBufExt *sbx = buffer_tobuf(L);
  GCcdata *cd;
  ctype_loadffi(L);
  cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
  *(void **)cdataptr(cd) = sbx->r;
  setcdataV(L, L->top++, cd);
  setintV(L->top++, sbufxlen(sbx));
  return 2;
}
#endif

LJLIB_CF(buffer_method_encode)		LJLIB_REC(.)
{
  SBufExt *sbx = buffer_tobufw(L);
  cTValue *o = lj_lib_checkany(L, 2);
  lj_serialize_put(sbx, o);
  lj_gc_check(L);
  L->top = L->base+1;  /* Chain buffer object. */
  return 1;
}

LJLIB_CF(buffer_method_decode)		LJLIB_REC(.)
{
  SBufExt *sbx = buffer_tobufw(L);
  setnilV(L->top++);
  sbx->r = lj_serialize_get(sbx, L->top-1);
  lj_gc_check(L);
  return 1;
}

LJLIB_CF(buffer_method___gc)
{
  SBufExt *sbx = buffer_tobuf(L);
  lj_bufx_free(L, sbx);
  return 0;
}

LJLIB_CF(buffer_method___tostring)	LJLIB_REC(.)
{
  SBufExt *sbx = buffer_tobuf(L);
  setstrV(L, L->top-1, lj_str_new(L, sbx->r, sbufxlen(sbx)));
  lj_gc_check(L);
  return 1;
}

LJLIB_CF(buffer_method___len)		LJLIB_REC(.)
{
  SBufExt *sbx = buffer_tobuf(L);
  setintV(L->top-1, (int32_t)sbufxlen(sbx));
  return 1;
}

LJLIB_PUSH("buffer") LJLIB_SET(__metatable)
LJLIB_PUSH(top-1) LJLIB_SET(__index)

/* -- Buffer library functions -------------------------------------------- */

#define LJLIB_MODULE_buffer

LJLIB_PUSH(top-2) LJLIB_SET(!)  /* Set environment. */

LJLIB_CF(buffer_new)
{
  MSize sz = 0;
  int targ = 1;
  GCtab *env, *dict_str = NULL, *dict_mt = NULL;
  GCudata *ud;
  SBufExt *sbx;
  if (L->base < L->top && !tvistab(L->base)) {
    targ = 2;
    if (!tvisnil(L->base))
      sz = (MSize)lj_lib_checkintrange(L, 1, 0, LJ_MAX_BUF);
  }
  if (L->base+targ-1 < L->top) {
    GCtab *options = lj_lib_checktab(L, targ);
    cTValue *opt_dict, *opt_mt;
    opt_dict = lj_tab_getstr(options, lj_str_newlit(L, "dict"));
    if (opt_dict && tvistab(opt_dict)) {
      dict_str = tabV(opt_dict);
      lj_serialize_dict_prep_str(L, dict_str);
    }
    opt_mt = lj_tab_getstr(options, lj_str_newlit(L, "metatable"));
    if (opt_mt && tvistab(opt_mt)) {
      dict_mt = tabV(opt_mt);
      lj_serialize_dict_prep_mt(L, dict_mt);
    }
  }
  env = tabref(curr_func(L)->c.env);
  ud = lj_udata_new(L, sizeof(SBufExt), env);
  ud->udtype = UDTYPE_BUFFER;
  /* NOBARRIER: The GCudata is new (marked white). */
  setgcref(ud->metatable, obj2gco(env));
  setudataV(L, L->top++, ud);
  sbx = (SBufExt *)uddata(ud);
  lj_bufx_init(L, sbx);
  setgcref(sbx->dict_str, obj2gco(dict_str));
  setgcref(sbx->dict_mt, obj2gco(dict_mt));
  if (sz > 0) lj_buf_need2((SBuf *)sbx, sz);
  lj_gc_check(L);
  return 1;
}

LJLIB_CF(buffer_encode)			LJLIB_REC(.)
{
  cTValue *o = lj_lib_checkany(L, 1);
  setstrV(L, L->top++, lj_serialize_encode(L, o));
  lj_gc_check(L);
  return 1;
}

LJLIB_CF(buffer_decode)			LJLIB_REC(.)
{
  GCstr *str = lj_lib_checkstrx(L, 1);
  setnilV(L->top++);
  lj_serialize_decode(L, L->top-1, str);
  lj_gc_check(L);
  return 1;
}

/* ------------------------------------------------------------------------ */

#include "lj_libdef.h"

int luaopen_string_buffer(lua_State *L)
{
  LJ_LIB_REG(L, NULL, buffer_method);
  lua_getfield(L, -1, "__tostring");
  lua_setfield(L, -2, "tostring");
  LJ_LIB_REG(L, NULL, buffer);
  return 1;
}

#endif