Annotation of sbbs/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.9 2004/12/30 10:59:16 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 2004 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,TRUE);
                     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_BOOLEAN:
                     92:                        *rval = BOOLEAN_TO_JSVAL(v->value.b);
                     93:                        break;
                     94:                case JSTYPE_NUMBER:
                     95:                        JS_NewNumberValue(cx,v->value.n,rval);
                     96:                        break;
                     97:                case JSTYPE_STRING:
                     98:                        if(v->value.s) {
                     99:                                *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,v->value.s));
                    100:                                if(!peek)
                    101:                                        free(v->value.s);
                    102:                        }
                    103:                        break;
                    104:                case JSTYPE_ARRAY:
                    105:                case JSTYPE_OBJECT:
                    106:                        obj = JS_DefineObject(cx, parent, v->name, NULL, NULL
                    107:                                ,JSPROP_ENUMERATE);
                    108:                        for(pv=v+1,count++;memcmp(pv,&term,sizeof(term));pv+=decoded,count+=decoded) {
                    109:                                decoded=js_decode_value(cx,obj,pv,&prop_val,peek);
                    110:                                if(v->type==JSTYPE_ARRAY)
                    111:                                        JS_SetElement(cx,obj,index++,&prop_val);
                    112:                                else
                    113:                                        JS_DefineProperty(cx, obj, pv->name, prop_val,NULL,NULL,JSPROP_ENUMERATE);
                    114:                        }
                    115:                        *rval = OBJECT_TO_JSVAL(obj);
                    116:                        break;
                    117:        }
                    118:        return(count);
                    119: }
                    120: 
                    121: /* Queue Object Methods */
                    122: 
                    123: static JSBool
                    124: js_poll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    125: {
                    126:        msg_queue_t*    q;
                    127:        queued_value_t* v;
                    128:        int32 timeout=0;
                    129: 
                    130:        if((q=(msg_queue_t*)JS_GetPrivate(cx,obj))==NULL) {
                    131:                JS_ReportError(cx,getprivate_failure,WHERE);
                    132:                return(JS_FALSE);
                    133:        }
                    134: 
                    135:        if(argc)        /* timeout specified */
                    136:                JS_ValueToInt32(cx,argv[0],&timeout);
                    137: 
                    138:        if((v=msgQueuePeek(q,timeout))==NULL)
                    139:                *rval = JSVAL_FALSE;
                    140:        else if(v->name!=NULL && v->name[0])
                    141:                *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,v->name));
                    142:        else
                    143:                *rval = JSVAL_TRUE;
                    144: 
                    145:        return(JS_TRUE);
                    146: }
                    147: 
                    148: static JSBool
                    149: js_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    150: {
                    151:        msg_queue_t* q;
                    152:        queued_value_t  find_v;
                    153:        queued_value_t* v;
                    154: 
                    155:        if((q=(msg_queue_t*)JS_GetPrivate(cx,obj))==NULL) {
                    156:                JS_ReportError(cx,getprivate_failure,WHERE);
                    157:                return(JS_FALSE);
                    158:        }
                    159: 
                    160:        if(argc) {      /* value named specified */
                    161:                ZERO_VAR(find_v);
                    162:                SAFECOPY(find_v.name,JS_GetStringBytes(JS_ValueToString(cx,argv[0])));
                    163:                v=msgQueueFind(q,&find_v,sizeof(find_v.name));
                    164:        } else
                    165:                v=msgQueueRead(q, /* timeout */0);
                    166: 
                    167:        js_decode_value(cx, obj, v, rval, /* peek */FALSE);
                    168: 
                    169:        FREE_AND_NULL(v);
                    170: 
                    171:        return(JS_TRUE);
                    172: }
                    173: 
                    174: static JSBool
                    175: js_peek(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    176: {
                    177:        msg_queue_t*    q;
                    178:        queued_value_t* v;
                    179: 
                    180:        if((q=(msg_queue_t*)JS_GetPrivate(cx,obj))==NULL) {
                    181:                JS_ReportError(cx,getprivate_failure,WHERE);
                    182:                return(JS_FALSE);
                    183:        }
                    184: 
                    185:        v=msgQueuePeek(q, /* timeout */0);
                    186: 
                    187:        js_decode_value(cx, obj, v, rval, /* peek */TRUE);
                    188: 
                    189:        FREE_AND_NULL(v);
                    190: 
                    191:        return(JS_TRUE);
                    192: }
                    193: 
                    194: static queued_value_t* js_encode_value(JSContext *cx, jsval val, char* name
                    195:                                                                           ,queued_value_t* v, size_t* count)
                    196: {
                    197:        jsint       i;
                    198:        jsval           prop_name;
                    199:        jsval           prop_val;
                    200:     JSObject*  obj;
                    201:        JSIdArray*      id_array;
                    202:        queued_value_t* nv;
                    203: 
                    204:        if((nv=realloc(v,((*count)+1)*sizeof(queued_value_t)))==NULL) {
                    205:                if(v) free(v);
                    206:                return(NULL);
                    207:        }
                    208:        v=nv;
                    209:        nv=v+(*count);
                    210:        memset(nv,0,sizeof(queued_value_t));
                    211:        (*count)++;
                    212: 
                    213:        if(name!=NULL)
                    214:                SAFECOPY(nv->name,name);
                    215: 
                    216:        switch(JSVAL_TAG(val)) {
                    217:                case JSVAL_BOOLEAN:
                    218:                        nv->type=JSTYPE_BOOLEAN;
                    219:                        nv->value.b=JSVAL_TO_BOOLEAN(val);
                    220:                        break;
                    221:                case JSVAL_OBJECT:
                    222:                        nv->type=JSTYPE_OBJECT;
                    223:                        obj = JSVAL_TO_OBJECT(val);
                    224: 
                    225:                        if(JSVAL_IS_NULL(val))
                    226:                                break;
                    227: 
                    228:                        if(JS_IsArrayObject(cx, obj))
                    229:                                nv->type=JSTYPE_ARRAY;
                    230: 
                    231:                        if((id_array=JS_Enumerate(cx,obj))==NULL) {
                    232:                                free(v);
                    233:                                return(NULL);
                    234:                        }
                    235:                        for(i=0; i<id_array->length; i++)  {
                    236:                                /* property name */
                    237:                                JS_IdToValue(cx,id_array->vector[i],&prop_name);
                    238:                                if(JSVAL_IS_STRING(prop_name)) {
                    239:                                        name=JS_GetStringBytes(JSVAL_TO_STRING(prop_name));
                    240:                                        /* value */
                    241:                                        JS_GetProperty(cx,obj,name,&prop_val);
                    242:                                } else {
                    243:                                        name=NULL;
                    244:                                        JS_GetElement(cx,obj,i,&prop_val);
                    245:                                }
                    246:                                if((v=js_encode_value(cx,prop_val,name,v,count))==NULL)
                    247:                                        break;
                    248:                        }
                    249:                        v=js_encode_value(cx,JSVAL_VOID,NULL,v,count);  /* terminate object */
                    250:                        break;
                    251:                default:
                    252:                        if(JSVAL_IS_NUMBER(val)) {
                    253:                                nv->type = JSTYPE_NUMBER;
                    254:                                JS_ValueToNumber(cx,val,&nv->value.n);
                    255:                        } else if(JSVAL_IS_VOID(val)) {
                    256:                                nv->type = JSTYPE_VOID;
                    257:                        } else {
                    258:                                nv->type= JSTYPE_STRING;
                    259:                                nv->value.s = strdup(JS_GetStringBytes(JS_ValueToString(cx,val)));
                    260:                        }
                    261:                        break;
                    262:        }
                    263: 
                    264:        return(v);
                    265: }
                    266: 
                    267: BOOL js_enqueue_value(JSContext *cx, msg_queue_t* q, jsval val, char* name)
                    268: {
                    269:        queued_value_t* v;
                    270:        size_t                  count=0;
                    271:        BOOL                    result;
                    272: 
                    273:        if((v=js_encode_value(cx,val,name,NULL,&count))==NULL || count<1)
                    274:                return(FALSE);
                    275: 
                    276:        result=msgQueueWrite(q,v,count*sizeof(queued_value_t));
                    277:        free(v);
                    278:        return(result);
                    279: }
                    280: 
                    281: static JSBool
                    282: js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    283: {
                    284:        uintN                   argn=0;
                    285:        msg_queue_t*    q;
                    286:        jsval                   val;
                    287:        char*                   name=NULL;
                    288: 
                    289:        if((q=(msg_queue_t*)JS_GetPrivate(cx,obj))==NULL) {
                    290:                JS_ReportError(cx,getprivate_failure,WHERE);
                    291:                return(JS_FALSE);
                    292:        }
                    293: 
                    294:        val = argv[argn++];
                    295: 
                    296:        if(argn < argc)
                    297:                name=JS_GetStringBytes(JS_ValueToString(cx,argv[argn++]));
                    298: 
                    299:        *rval = BOOLEAN_TO_JSVAL(js_enqueue_value(cx, q, val, name));
                    300: 
                    301:        return(JS_TRUE);
                    302: }
                    303: 
                    304: /* Queue Object Properites */
                    305: enum {
                    306:         QUEUE_PROP_NAME
                    307:        ,QUEUE_PROP_DATA_WAITING
                    308:        ,QUEUE_PROP_READ_LEVEL
                    309:        ,QUEUE_PROP_WRITE_LEVEL
                    310: };
                    311: 
                    312: #ifdef _DEBUG
                    313: static char* queue_prop_desc[] = {
                    314:         "name of the queue (if it has one)"
                    315:        ,"<i>true</i> if data is waiting to be read from queue"
                    316:        ,"number of values in the read queue"
                    317:        ,"number of values in the write qeueue"
                    318:        ,NULL
                    319: };
                    320: #endif
                    321: 
                    322: static JSBool js_queue_get(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
                    323: {
                    324:     jsint                      tiny;
                    325:        msg_queue_t*    q;
                    326: 
                    327:        if((q=(msg_queue_t*)JS_GetPrivate(cx,obj))==NULL) {
                    328:                JS_ReportError(cx,getprivate_failure,WHERE);
                    329:                return(JS_FALSE);
                    330:        }
                    331: 
                    332:     tiny = JSVAL_TO_INT(id);
                    333: 
                    334:        switch(tiny) {
                    335:                case QUEUE_PROP_NAME:
                    336:                        if(q->name!=NULL && q->name[0])
                    337:                                *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,q->name));
                    338:                        break;
                    339:                case QUEUE_PROP_DATA_WAITING:
                    340:                        *vp = BOOLEAN_TO_JSVAL(INT_TO_BOOL(msgQueueReadLevel(q)));
                    341:                        break;
                    342:                case QUEUE_PROP_READ_LEVEL:
                    343:                        *vp = INT_TO_JSVAL(msgQueueReadLevel(q));
                    344:                        break;
                    345:                case QUEUE_PROP_WRITE_LEVEL:
                    346:                        *vp = INT_TO_JSVAL(msgQueueWriteLevel(q));
                    347:                        break;
                    348:        }
                    349:        return(JS_TRUE);
                    350: }
                    351: 
                    352: #define QUEUE_PROP_FLAGS JSPROP_ENUMERATE|JSPROP_READONLY
                    353: 
                    354: static jsSyncPropertySpec js_queue_properties[] = {
                    355: /*              name                           ,tinyid                                 ,flags,                         ver     */
                    356: 
                    357:        {       "name"                          ,QUEUE_PROP_NAME                ,QUEUE_PROP_FLAGS,      312 },
                    358:        {       "data_waiting"          ,QUEUE_PROP_DATA_WAITING,QUEUE_PROP_FLAGS,      312 },
                    359:        {       "read_level"            ,QUEUE_PROP_READ_LEVEL  ,QUEUE_PROP_FLAGS,      312 },
                    360:        {       "write_level"           ,QUEUE_PROP_WRITE_LEVEL ,QUEUE_PROP_FLAGS,      312 },
                    361:        {0}
                    362: };
                    363: 
                    364: static JSClass js_queue_class = {
                    365:      "Queue"                           /* name                 */
                    366:     ,JSCLASS_HAS_PRIVATE       /* flags                */
                    367:        ,JS_PropertyStub                /* addProperty  */
                    368:        ,JS_PropertyStub                /* delProperty  */
                    369:        ,js_queue_get                   /* getProperty  */
                    370:        ,JS_PropertyStub                /* setProperty  */
                    371:        ,JS_EnumerateStub               /* enumerate    */
                    372:        ,JS_ResolveStub                 /* resolve              */
                    373:        ,JS_ConvertStub                 /* convert              */
                    374:        ,js_finalize_queue              /* finalize             */
                    375: };
                    376: 
                    377: static jsSyncMethodSpec js_queue_functions[] = {
                    378:        {"poll",                js_poll,                0,      JSTYPE_UNDEF,   "[timeout]"
                    379:        ,JSDOCSTR("wait for a value on the queue for up to <i>timeout</i> milliseconds "
                    380:                "(default: <i>infinite</i>), returns <i>true</i> or the <i>name</i> (string) of "
                    381:                "the value waiting (if it has one), or <i>false</i> if no values are waiting")
                    382:        ,312
                    383:        },
                    384:        {"read",                js_read,                0,      JSTYPE_UNDEF,   "[name]"
                    385:        ,JSDOCSTR("read a value from the queue, if <i>name</i> not specified, reads next value "
                    386:                "from the bottom of the queue")
                    387:        ,312
                    388:        },
                    389:        {"peek",                js_peek,                0,      JSTYPE_UNDEF,   ""
                    390:        ,JSDOCSTR("peek at the value at the bottom of the queue")
                    391:        ,312
                    392:        },
                    393:        {"write",               js_write,               0,      JSTYPE_BOOLEAN, "value [,name]"
                    394:        ,JSDOCSTR("write a value (optionally named) to the queue")
                    395:        ,312
                    396:        },
                    397:        {0}
                    398: };
                    399: 
                    400: /* Queue Constructor (creates queue) */
                    401: 
                    402: static JSBool
                    403: js_queue_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    404: {
                    405:        uintN                   argn=0;
                    406:        char*                   name=NULL;
                    407:        int32                   flags=MSG_QUEUE_BIDIR;
                    408:        msg_queue_t*    q=NULL;
                    409:        list_node_t*    n;
                    410: 
                    411:        *rval = JSVAL_VOID;
                    412: 
                    413:        if((q=(msg_queue_t*)malloc(sizeof(msg_queue_t)))==NULL) {
                    414:                JS_ReportError(cx,"malloc failed");
                    415:                return(JS_FALSE);
                    416:        }
                    417:        memset(q,0,sizeof(msg_queue_t));
                    418: 
                    419:        if(argn<argc && JSVAL_IS_STRING(argv[argn]))
                    420:                name=JS_GetStringBytes(JS_ValueToString(cx,argv[argn++]));
                    421: 
                    422:        if(argn<argc && JSVAL_IS_NUMBER(argv[argn]))
                    423:                JS_ValueToInt32(cx,argv[argn++],&flags);
                    424: 
                    425:        if(name!=NULL) {
                    426:                for(n=listFirstNode(&named_queues);n!=NULL;n=listNextNode(n))
                    427:                        if((q=n->data)!=NULL && !stricmp(q->name,name))
                    428:                                break;
                    429:                if(n==NULL)
                    430:                        q=NULL;
                    431:        }
                    432: 
                    433:        if(q==NULL) {
                    434:                q=msgQueueInit(NULL,flags);
                    435:                if(name!=NULL)
                    436:                        SAFECOPY(q->name,name);
                    437:                listPushNode(&named_queues,q);
                    438:        } else
                    439:                msgQueueAttach(q);
                    440: 
                    441:        if(!JS_SetPrivate(cx, obj, q)) {
                    442:                JS_ReportError(cx,"JS_SetPrivate failed");
                    443:                return(JS_FALSE);
                    444:        }
                    445: 
                    446:        if(!js_DefineSyncProperties(cx, obj, js_queue_properties)) {
                    447:                JS_ReportError(cx,"js_DefineSyncProperties failed");
                    448:                return(JS_FALSE);
                    449:        }
                    450: 
                    451:        if(!js_DefineSyncMethods(cx, obj, js_queue_functions, FALSE)) {
                    452:                JS_ReportError(cx,"js_DefineSyncMethods failed");
                    453:                return(JS_FALSE);
                    454:        }
                    455: 
                    456: #ifdef _DEBUG
                    457:        js_DescribeSyncObject(cx,obj,"Class for bi-directional message queues. "
                    458:                "Used for inter-thread/module communications.", 312);
                    459:        js_DescribeSyncConstructor(cx,obj,"To create a new (named) Queue object: "
                    460:                "<tt>var q = new Queue(<i>name</i>)</tt>");
                    461:        js_CreateArrayOfStrings(cx, obj, "_property_desc_list", queue_prop_desc, JSPROP_READONLY);
                    462: #endif
                    463: 
                    464:        return(JS_TRUE);
                    465: }
                    466: 
                    467: JSObject* DLLCALL js_CreateQueueClass(JSContext* cx, JSObject* parent)
                    468: {
                    469:        JSObject*       obj;
                    470: 
                    471:        obj = JS_InitClass(cx, parent, NULL
                    472:                ,&js_queue_class
                    473:                ,js_queue_constructor
                    474:                ,0      /* number of constructor args */
                    475:                ,NULL /* props, specified in constructor */
                    476:                ,NULL /* funcs, specified in constructor */
                    477:                ,NULL
                    478:                ,NULL);
                    479: 
                    480:        return(obj);
                    481: }
                    482: 
                    483: JSObject* DLLCALL js_CreateQueueObject(JSContext* cx, JSObject* parent, char *name, msg_queue_t* q)
                    484: {
                    485:        JSObject*               obj;
                    486: 
                    487:        if(name==NULL)
                    488:            obj = JS_NewObject(cx, &js_queue_class, NULL, parent);
                    489:        else
                    490:                obj = JS_DefineObject(cx, parent, name, &js_queue_class, NULL
                    491:                        ,JSPROP_ENUMERATE|JSPROP_READONLY);
                    492: 
                    493:        if(obj==NULL)
                    494:                return(NULL);
                    495: 
                    496:        if(!js_DefineSyncProperties(cx, obj, js_queue_properties))
                    497:                return(NULL);
                    498: 
                    499:        if(!JS_SetPrivate(cx, obj, q))
                    500:                return(NULL);
                    501: 
                    502:        if (!js_DefineSyncMethods(cx, obj, js_queue_functions, FALSE)) 
                    503:                return(NULL);
                    504: 
                    505:        return(obj);
                    506: }
                    507: 
                    508: 

unix.superglobalmegacorp.com

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