/* Copyright (c) 1998,1999 Stanley J. Brooks
* All rights reserved.
*
* You may redistribute under the terms of either the GNU General Public
* License or the Perl Artistic License.
*/
#include <ctype.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <slang.h>
#include <sys/types.h>
/* this was just to verify that cp0 will be an slstring
static int is_same(char *cp0)
{
char *cp1;
if (!SLang_pop_slstring(&cp1)) {
SLang_free_slstring(cp1);
return (cp0 == cp1);
}
return 0;
}
*/
static int is_uppers(unsigned char *cp)
{
unsigned char ch;
while ((ch=*cp++)) if (!isalpha(ch) || ch != UPPER_CASE(ch)) return 0;
return 1;
}
static int is_lowers(unsigned char *cp)
{
unsigned char ch;
while ((ch=*cp++)) if (!isalpha(ch) || ch != LOWER_CASE(ch)) return 0;
return 1;
}
/* this one depends on C locale: */
static int is_alnums(unsigned char *cp)
{
unsigned char ch;
while ((ch=*cp++)) if (!isalnum(ch)) return 0;
return 1;
}
static int is_digits(unsigned char *cp)
{
unsigned char ch;
while ((ch=*cp++)) if (!isdigit(ch)) return 0;
return 1;
}
/* [sjb] new builtin _time(), so remove this... */
static int unix_time(void)
{
return (int) time(NULL);
}
/* string = cut_list_element(string,string-to-cut,delim) */
static void cut_list_element(char* cp0, char* cut, int *delim)
{
char *cp,*out;
char ch0,ch;
int len,dl = (char) *delim;
if (!(cp0 = SLmake_string(cp0))) {
SLang_verror(SL_MALLOC_ERROR,"Problem making string");
return;
}
len=strlen(cut);
ch0=*cut;
for (cp=out=cp0; (ch=*cp); ) {
if ((!ch0 || (ch==ch0 && !memcmp(cp,cut,len)))
&& (!cp[len]||cp[len]==dl)) {
cp+=len;
if (!*cp++) {
if (out>cp0) out--;
break;
}
}else{
while((ch=*cp++) && ch!=dl) *out++=ch;
if (!ch) break;
*out++=ch;
}
}
*out='\0';
SLang_push_malloced_string(cp0);
/* ^^ this frees it, do don't bother with realloc */
return;
}
static int SLirc_index(char *cp, int *c)
{
register char *p=cp;
register char ch;
register char ch0=*c;
while ((ch=*p++))
if (ch==ch0) return p-cp;
return 0;
}
static int SLirc_rindex(char *cp, int *c)
{
register char *p=cp;
char *q=NULL;
register char ch;
register char ch0=*c;
while ((ch=*p++))
if (ch==ch0) q=p;
if (q) return(q-cp);
return 0;
}
static void chop_1st(char* cp0)
{
char *cp;
cp = cp0;
if (*cp) cp++;
SLang_push_string(cp);
return;
}
static void chop_last(char *cp0)
{
char *cp1;
int i;
i = strlen(cp0);
if (!i) i++;
cp1 = (char*) SLmalloc(i);
if (cp1) {
if (--i) (void)memcpy(cp1,cp0,i);
*(cp1+i) = '\0';
i = SLang_push_malloced_string(cp1);
if (i != -1) return;
}
SLang_verror(SL_MALLOC_ERROR,"Problem making string");
}
/* if input string ends with "\n" or "\r\n",
* push string less that.
* eg: s = chomp(s);
*/
static void chomp(char *cp0)
{
char *p;
int r,i;
p = rindex(cp0,'\n');
if (!p || p[1])
i = strlen(p);
else {
if (*--p != '\r') p++;
i = p - cp0;
}
p = (char*) SLmalloc(i+1);
if (p) {
if (i) (void)memcpy(p,cp0,i);
p[i] = '\0';
r = SLang_push_malloced_string(p);
if (!r) return;
}
SLang_verror(SL_MALLOC_ERROR,"Problem making string");
return;
}
/* url_encode replaces various special chars by their %xx equivs
* and ' ' by '+'
* this is for urlencoded HTTP queries
*/
static void url_encode(char* p)
{
unsigned char ch;
char *s0,*s;
s0 = (char*) SLmalloc(3*strlen(p)+1); /* enough for maximum expansion */
if (!s0) return;
s = s0;
while((ch = *p++)) {
if (ch == ' ') { *s++ = '+'; continue; }
if ( (ch >= 'a' && ch <= 'z')
|| (ch >= 'A' && ch <= 'Z')
|| (ch >= 0xa0) /* iso-latin-1 chars */
|| (ch == '_') || (ch == '.') || (ch == '-') || (ch == '$') /* safe */
/* || (ch == '!') || (ch == '*') || (ch == '\'') */
/* || (ch == '(') || (ch == ')') || (ch == ',') */
)
{ *s++ = ch; continue;}
sprintf(s,"%%%.2X",ch); s+=3;
}
*s++ = 0;
(void) SLang_push_malloced_string(s0);
}
static int hexlate(unsigned char ch)
{
int r;
if (ch >= '0' && ch <= '9') r = ch - '0';
else {
ch &= ~0x20;
if (ch >= 'A' && ch <= 'F') r = ch + 10 - 'A';
else r = -1;
}
return r;
}
static void url_decode(char* p)
{
unsigned char ch;
char *s0,*s;
s0 = (char*) SLmalloc(strlen(p)+1); /* enough, can't expand. */
if (!s0) return;
s = s0;
while((ch = *p++)) {
if (ch == '+') ch = ' ';
if (ch == '%') {
int r1,r2;
if ( ((r1 = hexlate(p[0])) >= 0)
&& ((r2 = hexlate(p[1])) >= 0)
&& (r2 += r1<<4) )
{
p+=2; ch = r2;
}
}
*s++ = ch;
}
*s++ = 0;
(void) SLang_push_malloced_string(s0);
}
/* s_split(string,delimiter) splits string with respect to delim-char,
* pushing token strings onto stack, followed by the integer count
* of the tokens. The first token in the string is pushed LAST, so
* that it will be the 1st to be popped.
*
* My IMPRESSION is that any string on the stack *should* be a
* private copy in RAM, so it shouldn't be necessary to save & restore
* the delim's, but who knows? I might be wrong.
*
* LATER THOUGHTS: above is true when you pop via SLpop_string,
* but NOT if SLang_pop_slstring.
* Also, if the parameter is specified via SLANG_STRING_TYPE in
* the intrinsic declaration, then the pointer you get is an slstring,
* which MUST NOT be modified.
*
* Something I'm still not clear on: when param is indicated as
* SLANG_STRING_TYPE in intrinsic declaration, do you still need
* to do SLang_free_slstring() on it within the subroutine?
* I assume that answer is "no" because of ... intrin_strcmp() in
* slang's own slstd.c source-file
*/
static int s_split(char *cp0, int *delim)
{
char *cp,*cph,dl;
int pmct=0;
cp0 = SLmake_string(cp0);
if (!cp0) {
SLang_verror(SL_MALLOC_ERROR,"Problem making string");
return 0;
}
dl = (char)(*delim);
for (cph=cp0+strlen(cp0); cph>cp0; cph=--cp) {
*cph='\0';
for (cp=cph; cp>cp0 && *--cp!=dl; ); /* back up to delim */
if (cp>cp0) cp++;
SLang_push_string(cp);
pmct++;
}
SLfree(cp0);
return(pmct);
}
static void v_split(char *cp0,char *delims)
{
char *cp,*cph,dl;
cp0 = SLmake_string(cp0);
if (!cp0) {
SLang_verror(SL_MALLOC_ERROR,"Problem making string");
return;
}
for(cp=cp0; (dl=*delims++); cp=cph) {
cph=index(cp,dl);
if (!cph) break;
*cph='\0';
SLang_push_string(cp);
*cph++=dl; /* restore it! */
}
SLang_push_string(cp); /* the last piece */
SLfree(cp0);
if (dl) /* fell short */
do {
SLang_push_string("");
} while (*delims++);
}
static int is_prefix(char *cpa, char *cpb)
{
u_char cha,chb;
while((chb=*cpb++)) {
cha=*cpa++;
if (cha!=chb) return 0;
}
return 1;
}
static int is_prefix_i(char *cpa, char *cpb)
{
u_char cha,chb;
while((chb=*cpb++)) {
cha=*cpa++;
if (LOWER_CASE(cha)!=LOWER_CASE(chb)) return 0;
}
return 1;
}
static int streq(char *cpa, char *cpb)
{
u_char cha,chb;
while((chb=*cpb++)) {
cha=*cpa++;
if (cha!=chb) return 0;
}
return (*cpa)?0:1;
}
static int streq_i(char *cpa, char *cpb)
{
u_char cha,chb;
while((chb=*cpb++)) {
cha=*cpa++;
if (LOWER_CASE(cha)!=LOWER_CASE(chb)) return 0;
}
return (*cpa)?0:1;
}
static int u_strspn(char *cpa, char *cpb)
{
char *pa,*pb;
char cha,chb;
pa=cpa;
while((cha=*pa++)) {
for (pb = cpb; ((chb=*pb++)) && chb != cha;);
if (!chb) break;
}
return (--pa-cpa);
}
static int u_strcspn(char *cpa, char *cpb)
{
char *pa,*pb;
char cha,chb;
pa=cpa;
while((cha=*pa++)) {
for (pb = cpb; ((chb=*pb++)) && chb != cha;);
if (chb) break;
}
return (--pa-cpa);
}
/* The Intrinsics Table for LinkList stuff, and some misc */
static SLang_Intrin_Fun_Type Utils_Fun_Intrinsics[] =
{
MAKE_INTRINSIC_0("unix_time", unix_time, SLANG_INT_TYPE),
MAKE_INTRINSIC_S("is_uppers", is_uppers, SLANG_INT_TYPE),
MAKE_INTRINSIC_S("is_lowers", is_lowers, SLANG_INT_TYPE),
MAKE_INTRINSIC_S("is_alnums", is_alnums, SLANG_INT_TYPE),
MAKE_INTRINSIC_S("is_digits", is_digits, SLANG_INT_TYPE),
MAKE_INTRINSIC_SS("is_prefix", is_prefix, SLANG_INT_TYPE),
MAKE_INTRINSIC_SS("is_prefix_i", is_prefix_i, SLANG_INT_TYPE),
MAKE_INTRINSIC_SS("streq", streq, SLANG_INT_TYPE),
MAKE_INTRINSIC_SS("streq_i", streq_i, SLANG_INT_TYPE),
MAKE_INTRINSIC_SS("strspn", u_strspn, SLANG_INT_TYPE),
MAKE_INTRINSIC_SS("strcspn", u_strcspn, SLANG_INT_TYPE),
MAKE_INTRINSIC_SI("index", SLirc_index, SLANG_INT_TYPE),
MAKE_INTRINSIC_SI("rindex", SLirc_rindex, SLANG_INT_TYPE),
MAKE_INTRINSIC_S("chop_1st", chop_1st, SLANG_VOID_TYPE),
MAKE_INTRINSIC_S("chop_last", chop_last, SLANG_VOID_TYPE),
MAKE_INTRINSIC_S("chomp", chomp, SLANG_VOID_TYPE),
MAKE_INTRINSIC_S("url_encode", url_encode, SLANG_VOID_TYPE),
MAKE_INTRINSIC_S("url_decode", url_decode, SLANG_VOID_TYPE),
MAKE_INTRINSIC_SSI("cut_list_element", cut_list_element, SLANG_VOID_TYPE),
MAKE_INTRINSIC_SI("s_split", s_split, SLANG_INT_TYPE),
MAKE_INTRINSIC_SS("v_split", v_split, SLANG_VOID_TYPE),
SLANG_END_TABLE
};
int init_utils_module(void) __attribute__((unused));
int init_utils_module(void)
{
if (SLdefine_for_ifdef("UTILS")) {
fprintf(stderr,"utils-module: fail define_for_isdef(UTILS)\n");
return -1;
}
if (SLadd_intrin_fun_table(Utils_Fun_Intrinsics, "Utils")) return -1;
return 1;
}
syntax highlighted by Code2HTML, v. 0.9.1