Annotation of sbbs/sbbs3/js_queue.c, revision 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.