Skip to content

Instantly share code, notes, and snippets.

@stevedonovan
Last active August 3, 2016 16:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stevedonovan/71b1e2443602edee308aab07e233854b to your computer and use it in GitHub Desktop.
Save stevedonovan/71b1e2443602edee308aab07e233854b to your computer and use it in GitHub Desktop.
An extension module for Lily provding extra string functions.
include_directories("../src/")
add_library(xstr SHARED lily_xstr.c)
set_target_properties(
xstr
PROPERTIES
PREFIX ""
COMPILE_FLAGS "-fPIC -g"
)
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "lily_api_embed.h"
#include "lily_api_alloc.h"
#include "lily_api_value.h"
#include "lily_api_msgbuf.h"
/**
package xstr
Provides a few extra operations on strings; an iterator, the size of a string
in characters, and a means to read a whole file.
*/
// this is private to be core, so let's define it again ;)
static const char move_table[256] =
{
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/* 0 */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 1 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 2 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 3 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 4 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 5 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 6 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 7 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* A */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* B */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* C */ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* D */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* E */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
/* F */ 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/**
define next(s: String, index: Integer): Tuple[String,Integer]
Grab the following character at index. Returns a tuple containing
the character at the index, and the index of the next character.
The returned index is -1 for the last character; thereafter ["",-1]
is returned.
*/
void lily_xstr__next(lily_state *vm)
{
const char *input = lily_arg_string_raw(vm,0);
int index = lily_arg_integer(vm,1);
// how many chars in this character?
int to_copy = index > -1 ? move_table[(uint8_t)input[index]] : 0;
// make a copy!
lily_string_val *string_result = lily_new_raw_string_sized(input + index, to_copy);
// and let's move onto the next....
index += to_copy;
if (index > -1 && input[index] == 0) { // ALWAYS nul-terminated...
index = -1;
}
// pack the character and the next index into a tuple
lily_list_val *lv = lily_new_list_val_n(2);
lily_list_set_string(lv,0,string_result);
lily_list_set_integer(lv,1,index);
lily_return_tuple(vm,lv);
}
/**
define size (s: String): Integer
Number of _characters_ in a string
*/
void lily_xstr__size(lily_state *vm)
{
char *str = lily_arg_string_raw(vm,0);
int res = 0;
while (*str) {
++res;
str += move_table[(uint8_t)*str];
}
lily_return_integer(vm, res);
}
static lily_string_val *fill_string_from_file(FILE *f, int drop_lf)
{
size_t bufsize = 64;
char *buffer = lily_malloc(bufsize);
int pos = 0, nread;
int nbuf = bufsize/2;
while (1) {
nread = fread(buffer+pos,1,nbuf,f);
pos += nread;
if (nread < nbuf) {
if (drop_lf && nread > 0)
--pos;
buffer[pos] = '\0';
break;
}
if (pos >= bufsize) {
nbuf = bufsize;
bufsize *= 2;
buffer = lily_realloc(buffer,bufsize);
}
}
lily_string_val *sv = lily_new_raw_string_sized(buffer,pos);
lily_free(buffer);
return sv;
}
/**
define readall (f: File): String
Read the whole of a file as a string.
Does not check whether the resulting string is valid UTF-8.
*/
void lily_xstr__readall(lily_state *vm)
{
lily_file_val *filev = lily_arg_file(vm,0);
lily_file_ensure_readable(vm,filev);
lily_return_string(vm, fill_string_from_file(lily_file_get_raw(filev),0));
}
/**
define shell (cmd: String): String
Read all the output of a shell command using popen
*/
void lily_xstr__shell(lily_state *vm)
{
const char *cmd = lily_arg_string_raw(vm,0);
FILE *f = popen(cmd,"r");
lily_return_string(vm, fill_string_from_file(f,1));
pclose(f);
}
static void concat(lily_state *vm, lily_msgbuf *msgbuf, char ch, lily_list_val *lv)
{
int i;
lily_mb_flush(msgbuf);
for (i = 0; i < lily_list_num_values(lv); i++) {
lily_value *v = lily_list_value(lv,i);
if (i > 0)
lily_mb_add_char(msgbuf,ch);
lily_vm_add_value_to_msgbuf(vm, msgbuf, v);
}
}
/**
define print (values:1...)
Print several values
*/
void lily_xstr__print(lily_state *vm)
{
lily_list_val *lv = lily_arg_list(vm,0);
lily_msgbuf *msgbuf = lily_vm_msgbuf(vm);
concat(vm,msgbuf,'\t',lv);
lily_mb_add_char(msgbuf,'\n');
fputs(lily_mb_get(msgbuf),stdout);
lily_mb_flush(msgbuf);
}
/**
define concat(delim: String, values:1...):String
Concatenate some arbitrary values using the single-character delimiter
*/
void lily_xstr__concat(lily_state *vm)
{
const char *delim = lily_arg_string_raw(vm,0);
lily_list_val *lv = lily_arg_list(vm,1);
lily_msgbuf *msgbuf = lily_vm_msgbuf(vm);
concat(vm,msgbuf,delim[0],lv);
lily_return_string(vm,lily_new_raw_string(lily_mb_get(msgbuf)));
lily_mb_flush(msgbuf);
}
static int char_index(const char *s, int idx, char ch)
{
const char *P = strchr(s+idx,ch);
if (! P)
return -1;
else
return (int)((uintptr_t)P - (uintptr_t)s);
}
// note the assumption ;)
static int convert_i(char d)
{
return (int)d - (int)'0';
}
/**
define format(fmt: String, values:1...):String
A simplified Python-style formatter
*/
void lily_xstr__format(lily_state *vm)
{
const char *fmt = lily_arg_string_raw(vm,0);
lily_list_val *lv = lily_arg_list(vm,1);
int lsize = lily_list_num_values(lv);
lily_msgbuf *msgbuf = lily_vm_msgbuf(vm);
lily_mb_flush(msgbuf);
int idx = 0, last_idx = 0, i_def = 0;
while (last_idx != -1) {
idx = char_index(fmt,last_idx,'{');
if (idx > -1) {
if (idx > last_idx)
lily_mb_add_range(msgbuf,fmt,last_idx, idx); // just before {
// next value
int i = i_def;
idx++; // skip '{'
if (isdigit(fmt[idx])) {
i = convert_i(fmt[idx]);
idx++;
} else {
i = i_def++;
}
if (i >= lsize) {
lily_error(vm, SYM_CLASS_INDEXERROR, "too many format items");
}
idx++; // skip '}'
lily_value *v = lily_list_value(lv,i);
lily_vm_add_value_to_msgbuf(vm, msgbuf, v);
} else { // end of format string
lily_mb_add_range(msgbuf,fmt,last_idx, strlen(fmt));
}
last_idx = idx;
}
lily_return_string(vm,lily_new_raw_string(lily_mb_get(msgbuf)));
lily_mb_flush(msgbuf);
}
#include "dyna_xstr.h"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment