Annotation of sbbs/src/sbbs3/js_queue.c, revision 1.1.1.1

1.1       root        1: /* js_queue.c */
                      2: 
                      3: /* Synchronet JavaScript "Queue" Object */
                      4: 
                      5: /* $Id: js_queue.c,v 1.18 2006/06/28 22:50:27 rswindell Exp $ */
                      6: 
                      7: /****************************************************************************
                      8:  * @format.tab-size 4          (Plain Text/Source Code File Header)                    *
                      9:  * @format.use-tabs true       (see http://www.synchro.net/ptsc_hdr.html)              *
                     10:  *                                                                                                                                                     *
                     11:  * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html         *
                     12:  *                                                                                                                                                     *
                     13:  * This program is free software; you can redistribute it and/or                       *
                     14:  * modify it under the terms of the GNU General Public License                         *
                     15:  * as published by the Free Software Foundation; either version 2                      *
                     16:  * of the License, or (at your option) any later version.                                      *
                     17:  * See the GNU General Public License for more details: gpl.txt or                     *
                     18:  * http://www.fsf.org/copyleft/gpl.html                                                                                *
                     19:  *                                                                                                                                                     *
                     20:  * Anonymous FTP access to the most recent released source is available at     *
                     21:  * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net     *
                     22:  *                                                                                                                                                     *
                     23:  * Anonymous CVS access to the development source and modification history     *
                     24:  * is available at cvs.synchro.net:/cvsroot/sbbs, example:                                     *
                     25:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs login                       *
                     26:  *     (just hit return, no password is necessary)                                                     *
                     27:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src                *
                     28:  *                                                                                                                                                     *
                     29:  * For Synchronet coding style and modification guidelines, see                                *
                     30:  * http://www.synchro.net/source.html                                                                          *
                     31:  *                                                                                                                                                     *
                     32:  * You are encouraged to submit any modifications (preferably in Unix diff     *
                     33:  * format) via e-mail to [email protected]                                                                      *
                     34:  *                                                                                                                                                     *
                     35:  * Note: If this box doesn't appear square, then you need to fix your tabs.    *
                     36:  ****************************************************************************/
                     37: 
                     38: #include "sbbs.h"
                     39: #include "msg_queue.h"
                     40: 
                     41: typedef struct
                     42: {
                     43:        char    name[128];
                     44:        int             type;
                     45:        union {
                     46:                JSBool          b;
                     47:                jsdouble        n;
                     48:                char*           s;
                     49:        } value;
                     50: } queued_value_t;
                     51: 
                     52: link_list_t named_queues;
                     53: 
                     54: static const char* getprivate_failure = "line %d %s JS_GetPrivate failed";
                     55: 
                     56: /* Queue Destructor */
                     57: 
                     58: static void js_finalize_queue(JSContext *cx, JSObject *obj)
                     59: {
                     60:        msg_queue_t* q;
                     61:        list_node_t* n;
                     62: 
                     63:        if((q=(msg_queue_t*)JS_GetPrivate(cx,obj))==NULL)
                     64:                return;
                     65:        
                     66:        if(msgQueueDetach(q)==0 && (n=listFindNode(&named_queues,q,/* length=0 for ptr compare */0))!=NULL)
                     67:                listRemoveNode(&named_queues,n,FALSE);
                     68: 
                     69:        JS_SetPrivate(cx, obj, NULL);
                     70: }
                     71: 
                     72: static size_t js_decode_value(JSContext *cx, JSObject *parent
                     73:                                                           ,queued_value_t* v, jsval* rval, BOOL peek)
                     74: {
                     75:        size_t                  count=1;
                     76:        size_t                  decoded;
                     77:        queued_value_t* pv;
                     78:        queued_value_t  term;
                     79:        jsval   prop_val;
                     80:        jsuint  index=0;
                     81:        JSObject *obj;
                     82: 
                     83:        ZERO_VAR(term);
                     84: 
                     85:        *rval = JSVAL_VOID;
                     86: 
                     87:        if(v==NULL || v->type==JSTYPE_VOID)
                     88:                return(count);
                     89: 
                     90:        switch(v->type) {
                     91:                case JSTYPE_NULL:
                     92:                        *rval = JSVAL_NULL;
                     93:                        break;
                     94:                case JSTYPE_BOOLEAN:
                     95:                        *rval = BOOLEAN_TO_JSVAL(v->value.b);
                     96:                        break;
                     97:                case JSTYPE_NUMBER:
                     98:                        JS_NewNumberValue(cx,v->value.n,rval);
                     99:                        break;
                    100:                case JSTYPE_STRING:
                    101:                        if(v->value.s) {
                    102:                                *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,v->value.s));
                    103:                                if(!peek)
                    104:                                        free(v->value.s);
                    105:                        }
                    106:                        break;
                    107:                case JSTYPE_ARRAY:
                    108:                case JSTYPE_OBJECT:
                    109:                        obj = JS_DefineObject(cx, parent, v->name, NULL, NULL
                    110:                                ,JSPROP_ENUMERATE);
                    111:                        for(pv=v+1,count++;memcmp(pv,&term,sizeof(term));pv+=decoded,count+=decoded) {
                    112:                                decoded=js_decode_value(cx,obj,pv,&prop_val,peek);
                    113:                                if(v->type==JSTYPE_ARRAY)
                    114:                                        JS_SetElement(cx,obj,index++,&prop_val);
                    115:                                else
                    116:                                        JS_DefineProperty(cx, obj, pv->name, prop_val,NULL,NULL,JSPROP_ENUMERATE);
                    117:                        }
                    118:                        *rval = OBJECT_TO_JSVAL(obj);
                    119:                        break;
                    120:        }
                    121:        return(count);
                    122: }
                    123: 
                    124: /* Queue Object Methods */
                    125: 
                    126: static JSBool
                    127: js_poll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    128: {
                    129:        msg_queue_t*    q;
                    130:        queued_value_t* v;
                    131:        int32 timeout=0;
                    132: 
                    133:        if((q=(msg_queue_t*)JS_GetPrivate(cx,obj))==NULL) {
                    134:                JS_ReportError(cx,getprivate_failure,WHERE);
                    135:                return(JS_FALSE);
                    136:        }
                    137: 
                    138:        if(argc && JSVAL_IS_NUMBER(argv[0]))    /* timeout specified */
                    139:                JS_ValueToInt32(cx,argv[0],&timeout);
                    140: 
                    141:        if((v=msgQueuePeek(q,timeout))==NULL)
                    142:                *rval = JSVAL_FALSE;
                    143:        else if(v->name!=NULL && v->name[0])
                    144:                *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,v->name));
                    145:        else
                    146:                *rval = JSVAL_TRUE;
                    147: 
                    148:        return(JS_TRUE);
                    149: }
                    150: 
                    151: static JSBool
                    152: js_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    153: {
                    154:        msg_queue_t* q;
                    155:        queued_value_t  find_v;
                    156:        queued_value_t* v;
                    157:        int32 timeout=0;
                    158: 
                    159:        if((q=(msg_queue_t*)JS_GetPrivate(cx,obj))==NULL) {
                    160:                JS_ReportError(cx,getprivate_failure,WHERE);
                    161:                return(JS_FALSE);
                    162:        }
                    163: 
                    164:        if(JSVAL_IS_STRING(argv[0])) {  /* value named specified */
                    165:                ZERO_VAR(find_v);
                    166:                SAFECOPY(find_v.name,JS_GetStringBytes(JS_ValueToString(cx,argv[0])));
                    167:                v=msgQueueFind(q,&find_v,sizeof(find_v.name));
                    168:        } else {
                    169:                if(JSVAL_IS_NUMBER(argv[0]))
                    170:                        JS_ValueToInt32(cx,argv[0],&timeout);
                    171:                v=msgQueueRead(q, timeout);
                    172:        }
                    173: 
                    174:        if(v!=NULL) {
                    175:                js_decode_value(cx, obj, v, rval, /* peek */FALSE);
                    176:                free(v);
                    177:        }
                    178: 
                    179:        return(JS_TRUE);
                    180: }
                    181: 
                    182: static JSBool
                    183: js_peek(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    184: {
                    185:        msg_queue_t*    q;
                    186:        queued_value_t* v;
                    187:        int32 timeout=0;
                    188: 
                    189:        if((q=(msg_queue_t*)JS_GetPrivate(cx,obj))==NULL) {
                    190:                JS_ReportError(cx,getprivate_failure,WHERE);
                    191:                return(JS_FALSE);
                    192:        }
                    193: 
                    194:        if(argc && JSVAL_IS_NUMBER(argv[0]))    /* timeout specified */
                    195:                JS_ValueToInt32(cx,argv[0],&timeout);
                    196: 
                    197:        if((v=msgQueuePeek(q, timeout))!=NULL) {
                    198:                js_decode_value(cx, obj, v, rval, /* peek */TRUE);
                    199:        }
                    200: 
                    201:        return(JS_TRUE);
                    202: }
                    203: 
                    204: static queued_value_t* js_encode_value(JSContext *cx, jsval val, char* name
                    205:                                                                           ,queued_value_t* v, size_t* count)
                    206: {
                    207:        jsint       i;
                    208:        jsval           prop_name;
                    209:        jsval           prop_val;
                    210:     JSObject*  obj;
                    211:        JSIdArray*      id_array;
                    212:        queued_value_t* nv;
                    213: 
                    214:        if((nv=realloc(v,((*count)+1)*sizeof(queued_value_t)))==NULL) {
                    215:                if(v) free(v);
                    216:                return(NULL);
                    217:        }
                    218:        v=nv;
                    219:        nv=v+(*count);
                    220:        memset(nv,0,sizeof(queued_value_t));
                    221:        (*count)++;
                    222: 
                    223:        if(name!=NULL)
                    224:                SAFECOPY(nv->name,name);
                    225: 
                    226:        switch(JSVAL_TAG(val)) {
                    227:                case JSVAL_BOOLEAN:
                    228:                        nv->type=JSTYPE_BOOLEAN;
                    229:                        nv->value.b=JSVAL_TO_BOOLEAN(val);
                    230:                        break;
                    231:                case JSVAL_OBJECT:
                    232:                        if(JSVAL_IS_NULL(val)) {
                    233:                                nv->type=JSTYPE_NULL;
                    234:                                break;
                    235:                        }
                    236:                        nv->type=JSTYPE_OBJECT;
                    237:                        obj = JSVAL_TO_OBJECT(val);
                    238: 
                    239:                        if(JS_IsArrayObject(cx, obj))
                    240:                                nv->type=JSTYPE_ARRAY;
                    241: 
                    242:                        if((id_array=JS_Enumerate(cx,obj))==NULL) {
                    243:                                free(v);
                    244:                                return(NULL);
                    245:                        }
                    246:                        for(i=0; i<id_array->length; i++)  {
                    247:                                /* property name */
                    248:                                JS_IdToValue(cx,id_array->vector[i],&prop_name);
                    249:                                if(JSVAL_IS_STRING(prop_name)) {
                    250:                                        name=JS_GetStringBytes(JSVAL_TO_STRING(prop_name));
                    251:                                        /* value */
                    252:                                        JS_GetProperty(cx,obj,name,&prop_val);
                    253:                                } else {
                    254:                                        name=NULL;
                    255:                                        JS_GetElement(cx,obj,i,&prop_val);
                    256:                                }
                    257:                                if((v=js_encode_value(cx,prop_val,name,v,count))==NULL)
                    258:                                        break;
                    259:                        }
                    260:                        v=js_encode_value(cx,JSVAL_VOID,NULL,v,count);  /* terminate object */
                    261:                        JS_DestroyIdArray(cx,id_array);
                    262:                        break;
                    263:                default:
                    264:                        if(JSVAL_IS_NUMBER(val)) {
                    265:                                nv->type = JSTYPE_NUMBER;
                    266:                                JS_ValueToNumber(cx,val,&nv->value.n);
                    267:                        } else if(JSVAL_IS_VOID(val)) {
                    268:                                nv->type = JSTYPE_VOID;
                    269:                        } else {
                    270:                                nv->type= JSTYPE_STRING;
                    271:                                nv->value.s = strdup(JS_GetStringBytes(JS_ValueToString(cx,val)));
                    272:                        }
                    273:                        break;
                    274:        }
                    275: 
                    276:        return(v);
                    277: }
                    278: 
                    279: BOOL js_enqueue_value(JSContext *cx, msg_queue_t* q, jsval val, char* name)
                    280: {
                    281:        queued_value_t* v;
                    282:        size_t                  count=0;
                    283:        BOOL                    result;
                    284: 
                    285:        if((v=js_encode_value(cx,val,name,NULL,&count))==NULL || count<1)
                    286:                return(FALSE);
                    287: 
                    288:        result=msgQueueWrite(q,v,count*sizeof(queued_value_t));
                    289:        free(v);
                    290:        return(result);
                    291: }
                    292: 
                    293: static JSBool
                    294: js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    295: {
                    296:        uintN                   argn=0;
                    297:        msg_queue_t*    q;
                    298:        jsval                   val;
                    299:        char*                   name=NULL;
                    300: 
                    301:        if((q=(msg_queue_t*)JS_GetPrivate(cx,obj))==NULL) {
                    302:                JS_ReportError(cx,getprivate_failure,WHERE);
                    303:                return(JS_FALSE);
                    304:        }
                    305: 
                    306:        val = argv[argn++];
                    307: 
                    308:        if(argn < argc)
                    309:                name=JS_GetStringBytes(JS_ValueToString(cx,argv[argn++]));
                    310: 
                    311:        *rval = BOOLEAN_TO_JSVAL(js_enqueue_value(cx, q, val, name));
                    312: 
                    313:        return(JS_TRUE);
                    314: }
                    315: 
                    316: /* Queue Object Properites */
                    317: enum {
                    318:         QUEUE_PROP_NAME
                    319:        ,QUEUE_PROP_DATA_WAITING
                    320:        ,QUEUE_PROP_READ_LEVEL
                    321:        ,QUEUE_PROP_WRITE_LEVEL
                    322: };
                    323: 
                    324: #ifdef BUILD_JSDOCS
                    325: static char* queue_prop_desc[] = {
                    326:         "name of the queue (if it has one)"
                    327:        ,"<i>true</i> if data is waiting to be read from queue"
                    328:        ,"number of values in the read queue"
                    329:        ,"number of values in the write qeueue"
                    330:        ,NULL
                    331: };
                    332: #endif
                    333: 
                    334: static JSBool js_queue_get(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
                    335: {
                    336:     jsint                      tiny;
                    337:        msg_queue_t*    q;
                    338: 
                    339:        if((q=(msg_queue_t*)JS_GetPrivate(cx,obj))==NULL) {
                    340:                JS_ReportError(cx,getprivate_failure,WHERE);
                    341:                return(JS_FALSE);
                    342:        }
                    343: 
                    344:     tiny = JSVAL_TO_INT(id);
                    345: 
                    346:        switch(tiny) {
                    347:                case QUEUE_PROP_NAME:
                    348:                        if(q->name!=NULL && q->name[0])
                    349:                                *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,q->name));
                    350:                        break;
                    351:                case QUEUE_PROP_DATA_WAITING:
                    352:                        *vp = BOOLEAN_TO_JSVAL(INT_TO_BOOL(msgQueueReadLevel(q)));
                    353:                        break;
                    354:                case QUEUE_PROP_READ_LEVEL:
                    355:                        *vp = INT_TO_JSVAL(msgQueueReadLevel(q));
                    356:                        break;
                    357:                case QUEUE_PROP_WRITE_LEVEL:
                    358:                        *vp = INT_TO_JSVAL(msgQueueWriteLevel(q));
                    359:                        break;
                    360:        }
                    361:        return(JS_TRUE);
                    362: }
                    363: 
                    364: #define QUEUE_PROP_FLAGS JSPROP_ENUMERATE|JSPROP_READONLY
                    365: 
                    366: static jsSyncPropertySpec js_queue_properties[] = {
                    367: /*              name                           ,tinyid                                 ,flags,                         ver     */
                    368: 
                    369:        {       "name"                          ,QUEUE_PROP_NAME                ,QUEUE_PROP_FLAGS,      312 },
                    370:        {       "data_waiting"          ,QUEUE_PROP_DATA_WAITING,QUEUE_PROP_FLAGS,      312 },
                    371:        {       "read_level"            ,QUEUE_PROP_READ_LEVEL  ,QUEUE_PROP_FLAGS,      312 },
                    372:        {       "write_level"           ,QUEUE_PROP_WRITE_LEVEL ,QUEUE_PROP_FLAGS,      312 },
                    373:        {0}
                    374: };
                    375: 
                    376: static JSClass js_queue_class = {
                    377:      "Queue"                           /* name                 */
                    378:     ,JSCLASS_HAS_PRIVATE       /* flags                */
                    379:        ,JS_PropertyStub                /* addProperty  */
                    380:        ,JS_PropertyStub                /* delProperty  */
                    381:        ,js_queue_get                   /* getProperty  */
                    382:        ,JS_PropertyStub                /* setProperty  */
                    383:        ,JS_EnumerateStub               /* enumerate    */
                    384:        ,JS_ResolveStub                 /* resolve              */
                    385:        ,JS_ConvertStub                 /* convert              */
                    386:        ,js_finalize_queue              /* finalize             */
                    387: };
                    388: 
                    389: static jsSyncMethodSpec js_queue_functions[] = {
                    390:        {"poll",                js_poll,                1,      JSTYPE_UNDEF,   "[timeout=<tt>0</tt>]"
                    391:        ,JSDOCSTR("wait for any value to be written to the queue for up to <i>timeout</i> milliseconds "
                    392:                "(default: <i>0</i>), returns <i>true</i> or the <i>name</i> (string) of "
                    393:                "the value waiting (if it has one), or <i>false</i> if no values are waiting")
                    394:        ,312
                    395:        },
                    396:        {"read",                js_read,                1,      JSTYPE_UNDEF,   "[string name] or [timeout=<tt>0</tt>]"
                    397:        ,JSDOCSTR("read a value from the queue, if <i>name</i> not specified, reads next value "
                    398:                "from the bottom of the queue (waiting up to <i>timeout</i> milliseconds)")
                    399:        ,313
                    400:        },
                    401:        {"peek",                js_peek,                1,      JSTYPE_UNDEF,   "[timeout=<tt>0</tt>]"
                    402:        ,JSDOCSTR("peek at the value at the bottom of the queue, "
                    403:                "wait up to <i>timeout</i> milliseconds for any value to be written "
                    404:                "(default: <i>0</i>)")
                    405:        ,313
                    406:        },
                    407:        {"write",               js_write,               1,      JSTYPE_BOOLEAN, "value [,name=<i>none</i>]"
                    408:        ,JSDOCSTR("write a value (optionally named) to the queue")
                    409:        ,312
                    410:        },
                    411:        {0}
                    412: };
                    413: 
                    414: /* Queue Constructor (creates queue) */
                    415: 
                    416: static JSBool
                    417: js_queue_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    418: {
                    419:        uintN                   argn=0;
                    420:        char*                   name=NULL;
                    421:        int32                   flags=MSG_QUEUE_BIDIR;
                    422:        msg_queue_t*    q=NULL;
                    423:        list_node_t*    n;
                    424: 
                    425:        *rval = JSVAL_VOID;
                    426: 
                    427: #if 0  /* This doesn't appear to be doing anything but leaking memory */
                    428:        if((q=(msg_queue_t*)malloc(sizeof(msg_queue_t)))==NULL) {
                    429:                JS_ReportError(cx,"malloc failed");
                    430:                return(JS_FALSE);
                    431:        }
                    432:        memset(q,0,sizeof(msg_queue_t));
                    433: #endif
                    434: 
                    435:        if(argn<argc && JSVAL_IS_STRING(argv[argn]))
                    436:                name=JS_GetStringBytes(JS_ValueToString(cx,argv[argn++]));
                    437: 
                    438:        if(argn<argc && JSVAL_IS_NUMBER(argv[argn]))
                    439:                JS_ValueToInt32(cx,argv[argn++],&flags);
                    440: 
                    441:        if(name!=NULL) {
                    442:                for(n=listFirstNode(&named_queues);n!=NULL;n=listNextNode(n))
                    443:                        if((q=n->data)!=NULL && !stricmp(q->name,name))
                    444:                                break;
                    445:                if(n==NULL)
                    446:                        q=NULL;
                    447:        }
                    448: 
                    449:        if(q==NULL) {
                    450:                q=msgQueueInit(NULL,flags);
                    451:                if(name!=NULL)
                    452:                        SAFECOPY(q->name,name);
                    453:                listPushNode(&named_queues,q);
                    454:        } else
                    455:                msgQueueAttach(q);
                    456: 
                    457:        if(!JS_SetPrivate(cx, obj, q)) {
                    458:                JS_ReportError(cx,"JS_SetPrivate failed");
                    459:                return(JS_FALSE);
                    460:        }
                    461: 
                    462:        if(!js_DefineSyncProperties(cx, obj, js_queue_properties)) {
                    463:                JS_ReportError(cx,"js_DefineSyncProperties failed");
                    464:                return(JS_FALSE);
                    465:        }
                    466: 
                    467:        if(!js_DefineSyncMethods(cx, obj, js_queue_functions, FALSE)) {
                    468:                JS_ReportError(cx,"js_DefineSyncMethods failed");
                    469:                return(JS_FALSE);
                    470:        }
                    471: 
                    472: #ifdef BUILD_JSDOCS
                    473:        js_DescribeSyncObject(cx,obj,"Class for bi-directional message queues. "
                    474:                "Used for inter-thread/module communications.", 312);
                    475:        js_DescribeSyncConstructor(cx,obj,"To create a new (named) Queue object: "
                    476:                "<tt>var q = new Queue(<i>name</i>)</tt>");
                    477:        js_CreateArrayOfStrings(cx, obj, "_property_desc_list", queue_prop_desc, JSPROP_READONLY);
                    478: #endif
                    479: 
                    480:        return(JS_TRUE);
                    481: }
                    482: 
                    483: JSObject* DLLCALL js_CreateQueueClass(JSContext* cx, JSObject* parent)
                    484: {
                    485:        JSObject*       obj;
                    486: 
                    487:        obj = JS_InitClass(cx, parent, NULL
                    488:                ,&js_queue_class
                    489:                ,js_queue_constructor
                    490:                ,0      /* number of constructor args */
                    491:                ,NULL /* props, specified in constructor */
                    492:                ,NULL /* funcs, specified in constructor */
                    493:                ,NULL
                    494:                ,NULL);
                    495: 
                    496:        return(obj);
                    497: }
                    498: 
                    499: JSObject* DLLCALL js_CreateQueueObject(JSContext* cx, JSObject* parent, char *name, msg_queue_t* q)
                    500: {
                    501:        JSObject*               obj;
                    502: 
                    503:        if(name==NULL)
                    504:            obj = JS_NewObject(cx, &js_queue_class, NULL, parent);
                    505:        else
                    506:                obj = JS_DefineObject(cx, parent, name, &js_queue_class, NULL
                    507:                        ,JSPROP_ENUMERATE|JSPROP_READONLY);
                    508: 
                    509:        if(obj==NULL)
                    510:                return(NULL);
                    511: 
                    512:        if(!js_DefineSyncProperties(cx, obj, js_queue_properties))
                    513:                return(NULL);
                    514: 
                    515:        if(!JS_SetPrivate(cx, obj, q))
                    516:                return(NULL);
                    517: 
                    518:        if (!js_DefineSyncMethods(cx, obj, js_queue_functions, FALSE)) 
                    519:                return(NULL);
                    520: 
                    521:        return(obj);
                    522: }
                    523: 
                    524: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.