builtins.cpp

来自「Shorthand是一个强大的脚本语言」· C++ 代码 · 共 710 行 · 第 1/2 页

CPP
710
字号
///////////////////////////////////////////////////////////////////////////////
// $Header: /shorthand/src/builtins.cpp 6     2/08/03 6:40a Arm $
//-----------------------------------------------------------------------------
// Project: ShortHand interpreter
// Author: Andrei Remenchuk <andrei@remenchuk.com>
//-----------------------------------------------------------------------------
// builtins.cpp: implementations of ShortHand built-in functions
///////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef WIN32
#include <unistd.h>
#endif

#include "builtins.h"
#include "module.h"
#include "except.h"
#include "http.h"
#include "cookie.h"
#include "sharray.h"
#include "hash.h"

#ifndef WIN32
static int min(int x, int y) { return x < y ? x : y; }
static int max(int x, int y) { return x > y ? x : y; }
#endif


ShhBuiltinList g_builtins;

static int set_globals()
{
    tzset();
    return 0;
}

static int dummy = set_globals();

ShhBuiltin::ShhBuiltin(const char* name, shorthand_function_t f, int argc)
: ShhFunction(name, argc)
{
    m_function = f;
    g_builtins.add(this);
}


ShhValue ShhBuiltin::execute(ShhModule* module, const ShhValueList& args) const
{
    int argc = args.size();
    if (m_argc > 0)
    {
        if (m_argc == 1 && argc == 0)
            throw new ShhFunctionException(9000, "function '%s' requires an argument", m_name.cstr());
        else if (argc < m_argc)
            throw new ShhFunctionException(9000, "function '%s' requires %d arguments", m_name.cstr(), m_argc);
    }
    return m_function(module, args);
}

void ShhBuiltin::paste_location(string& location)
{
    location = "as built-in function";
}


const ShhBuiltin* ShhBuiltinList::find(const char* name)
{
    for(int i=0,n=m_size; i<n; i++)
    {
        ShhBuiltin* b = get(i);
        if (stricmp(b->m_name, name) == 0) return b;
    }
    return NULL;
}




#define SHORTHAND_BUILTIN(name, argc) \
    ShhValue _shh_bi_impl_##name(ShhModule* module, const ShhValueList& args); \
 ShhBuiltin _shh_bi_desc_##name(#name, _shh_bi_impl_##name, argc); \
    ShhValue _shh_bi_impl_##name(ShhModule* module, const ShhValueList& args)

#define ARGC args.size()
#define ARG(i) args.get(i)
#define MAKE_STRING(s) module->scratch().strdup(s)



/**
 * exit()
 * stops script execution and send finish sending output
 * @return none
 */
SHORTHAND_BUILTIN(exit, 0)
{
    throw new ShhExitException();
}

/**
 * header(name,value): sets HTTP header
 * @return none
 */
SHORTHAND_BUILTIN(header, 2)
{
    HttpStream* stream = module->stream();
    if (stream->http_headers_sent())
    {
        throw new ShhFunctionException(9010, "Cannot set HTTP header value because headers have been already sent");
    }
    
    string name, value;
    
    ARG(0)->toString(name);
    ARG(1)->toString(value);
    
    stream->http_add_header(name, value);
    
    return ShhValue::EMPTY;
}

/**
 * jump(url)
 * redirects page to the supplied URL
 * 
 * @return none
 */
SHORTHAND_BUILTIN(redirect, 1)
{
    HttpStream* stream = module->stream();
    if (stream->http_headers_sent())
    {
        throw new ShhFunctionException(9011, "Cannot perform redirection because headers have been already sent");
    }
    
    string url;
    ARG(0)->toString(url);
    
    stream->http_add_header("Location", url);
    stream->http_set_response_code(302, "Moved");
    throw new ShhExitException();
}


/**
 * lc(s): lowercase string
 */
SHORTHAND_BUILTIN(lc, 1)
{
    string s; ARG(0)->toString(s);
    s.lowercase();

    char* result = module->scratch().strdup(s);
    return ShhValue(result);
}

/**
 * uc(s): uppercase string
 */
SHORTHAND_BUILTIN(uc, 1)
{
    string s; ARG(0)->toString(s);
    s.uppercase();
    char* result = module->scratch().strdup(s);
    return ShhValue(result);
}


/**
 * env(s): value of environment variable
 */
SHORTHAND_BUILTIN(env, 1)
{
    string s,tmp; ARG(0)->toString(s);
    const char* result = safe_getenv(s, tmp);
    if (result == NULL) result = "";
    return ShhValue(module->scratch().strdup(result));

}

/**
 * f(s): value of POST variable
 */
SHORTHAND_BUILTIN(F, 1)
{
    string name; ARG(0)->toString(name);
    const char* v = module->POST(name);
    return ShhValue(module->scratch().strdup(v));
}

/**
 * q(s): value of GET variable
 */
SHORTHAND_BUILTIN(Q, 1)
{
    string name; ARG(0)->toString(name);
    const char* v = module->GET(name);
    return ShhValue(module->scratch().strdup(v));
}


/**
 * length(s): length of string expression
 */
SHORTHAND_BUILTIN(length, 1)
{
    string value; ARG(0)->toString(value);
    return value.length();
}


static int random_seed = 0;

SHORTHAND_BUILTIN(rand, 0)
{
    int argc = args.size();
    
    int lo, hi;

    if (argc == 0) 
    {
        lo = 0;
        hi = 0x7FFFFFFF;
    }
    else if (argc == 1)
    {
        lo = 0;
        hi = ARG(0)->toInt();
    }
    else if (argc >= 2)
    {
        lo = ARG(0)->toInt();
        hi = ARG(1)->toInt();
    }

 
#ifdef WIN32
    
    if (random_seed == 0)
    {
        LARGE_INTEGER qw;
        QueryPerformanceCounter(&qw);
        srand( (int) qw.QuadPart );
	random_seed = 1;
    }
#else
    if (random_seed == 0)
    {
	int foo = (int) alloca(4);
	random_seed = getpid() ^ foo;
	srand(random_seed);
    }
#endif
    int r = abs(rand()<<24|rand()<<12|rand());

    int magnitude = hi - lo;
    if (magnitude <= 0) return r;
    else return lo + r%magnitude;
}



/**
 * formats(f,precision)
 * 
 * formats float number with specified precision (number of digits after decimal
 * point).
 * 
 * @return formatted string
 */
SHORTHAND_BUILTIN(format, 2)
{
    double value = ARG(0)->toFloat();
    int precision = ARG(1)->toInt();
    
    string spec; spec.printf("%%.%df", precision);
    ShhValue r(module->scratch().printf(spec.cstr(), value));
    return r;
}

/*
 * max(n1,n2,...) function
 */
SHORTHAND_BUILTIN(max, 2)
{
    int result = ARG(0)->toInt();
    for(int i=1,n=args.size(); i<n; i++)
    {
        int value = ARG(i)->toInt();
        result = result > value ? result : value;
    }
    ShhValue r(result);
    return r;
}

/*
 * min(n1,n2,...) function
 */
SHORTHAND_BUILTIN(min, 2)
{
    int result = ARG(0)->toInt();
    for(int i=1,n=args.size(); i<n; i++)
    {
        int value = ARG(i)->toInt();
        result = result < value ? result : value;
    }
    ShhValue r(result);
    return r;
}


/*
 * substring(s,start[,length) function
 * @param s source string
 * @param start starting index (from the end if negative)
 * @param length length
 *     
 */
SHORTHAND_BUILTIN(substring, 2)
{
    string s; ARG(0)->toString(s);
    int start = ARG(1)->toInt();
    int length = (args.size() > 2) ? ARG(2)->toInt() : -1;
    if (length == -1) length = s.length();
    
    string result;
    if (start < 0)
    {
        start = s.length() + start;
        int from = max(start, 0); 
            from = min(start, s.length());
        int to   = min(start+abs(length), s.length());
            to   = max(to, from);
        result.set(s.cstr()+from, to-from);
    }
    else
    {
        int from = max(start, 0); 
            from = min(start, s.length());
        int to   = min(start+abs(length), s.length());
            to   = max(to, from);
        result.set(s.cstr()+from, to-from);
    }
    
    ShhValue r(module->scratch().strdup(result));
    return r;
}


/**
 * strpos(haystack, needle).
 *

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?