DaoxGlyph* DaoxFont_LoadGlyph( DaoxFont *self, size_t codepoint ) { DaoxGlyph *glyph = DaoxGlyph_New(); stbtt_vertex *vertices = NULL; int id = stbtt_FindGlyphIndex( & self->info, codepoint ); int i, num_verts = stbtt_GetGlyphShape( & self->info, id, & vertices ); stbtt_GetGlyphHMetrics( & self->info, id, & glyph->advanceWidth, & glyph->leftSideBearing ); DMap_Insert( self->glyphs, (void*) codepoint, glyph ); DaoxPath_SetRelativeMode( glyph->shape, 0 ); for(i=0; i<num_verts; ++i){ stbtt_vertex_type x = vertices[i].x; stbtt_vertex_type y = vertices[i].y; stbtt_vertex_type cx = vertices[i].cx; stbtt_vertex_type cy = vertices[i].cy; switch( vertices[i].type ){ case STBTT_vmove : if( i ) DaoxPath_Close( glyph->shape ); DaoxPath_MoveTo( glyph->shape, x, y ); break; case STBTT_vline : DaoxPath_LineTo( glyph->shape, x, y ); break; case STBTT_vcurve : DaoxPath_QuadTo( glyph->shape, cx, cy, x, y ); break; } } if( i ) DaoxPath_Close( glyph->shape ); stbtt_FreeShape( & self->info, vertices ); return glyph; }
static void DMap_SortMethods( DMap *hash, DList *methods ) { DMap *map = DMap_New( DAO_DATA_STRING, 0 ); DString *name = DString_New(); DNode *it; daoint i, n; for(it=DMap_First(hash); it; it=DMap_Next(hash,it)){ if( it->value.pRoutine->overloads ){ DRoutines *one = it->value.pRoutine->overloads; for(i=0,n=one->routines->size; i<n; i++){ DaoRoutine *rout = one->routines->items.pRoutine[i]; DString_Assign( name, rout->routName ); DString_AppendChars( name, " " ); DString_Append( name, rout->routType->name ); DMap_Insert( map, name, (void*)rout ); } }else{ DaoRoutine *rout = it->value.pRoutine; DString_Assign( name, rout->routName ); DString_AppendChars( name, " " ); DString_Append( name, rout->routType->name ); DMap_Insert( map, name, (void*)rout ); } } DList_Clear( methods ); for(it=DMap_First(map); it; it=DMap_Next(map,it)) DList_Append( methods, it->value.pVoid ); DMap_Delete( map ); DString_Delete( name ); }
int DaoInterface_BindTo( DaoInterface *self, DaoType *type, DMap *binds ) { DNode *it; DMap *newbinds = NULL; DList *methods; void *pvoid[2]; daoint i, n, bl; /* XXX locking */ if( type->interfaces == NULL ) type->interfaces = DHash_New( DAO_DATA_VALUE, 0 ); pvoid[0] = type; pvoid[1] = self->abtype; if( (it = DMap_Find( type->interfaces, self )) ) return it->value.pVoid != NULL; if( binds && DMap_Find( binds, pvoid ) ) return 1; if( binds ==NULL ) newbinds = binds = DHash_New( DAO_DATA_VOID2, 0 ); DaoInterface_TempBind( self, type, binds ); methods = DList_New(0); DMap_SortMethods( self->methods, methods ); bl = DaoInterface_CheckBind( methods, type, binds ); DList_Delete( methods ); if( newbinds ) DMap_Delete( newbinds ); DMap_Insert( type->interfaces, self, bl ? self : NULL ); if( bl == 0 ) return 0; for(i=0,n=self->supers->size; i<n; i++){ DaoInterface *super = (DaoInterface*) self->supers->items.pValue[i]; if( DMap_Find( type->interfaces, super ) ) continue; DMap_Insert( type->interfaces, super, super ); } return 1; }
void DaoCallServer_AddTimedWait( DaoProcess *wait, DaoTaskEvent *event, double timeout ) { DaoCallServer *server; if( daoCallServer == NULL ) DaoCallServer_Init( mainVmSpace ); server = daoCallServer; DMutex_Lock( & server->mutex ); if( timeout >= 1E-27 ){ server->timestamp.value.real = timeout + Dao_GetCurrentTime(); server->timestamp.value.imag += 1; event->expiring = server->timestamp.value.real; DMap_Insert( server->waitings, & server->timestamp, event ); DMap_Insert( server->pending, event, NULL ); DCondVar_Signal( & server->condv2 ); }else{ event->expiring = -1.0; DaoCallServer_AddEvent( event ); DCondVar_Signal( & server->condv ); } if( wait->condv ){ /* // Need to suspend the native thread, for suspending inside code sections // for functional methods such as std.iterate(), mt.iterate() etc: */ wait->pauseType = DAO_PAUSE_NATIVE_THREAD; if( timeout > 0 ){ DCondVar_TimedWait( wait->condv, & server->mutex, timeout ); }else{ DCondVar_Wait( wait->condv, & server->mutex ); } wait->status = DAO_PROCESS_RUNNING; } DMutex_Unlock( & server->mutex ); }
void DaoCallServer_AddTimedWait( DaoProcess *wait, DaoTaskEvent *event, double timeout ) { DaoCallServer *server = daoCallServer; /* // The "wait" process may not be running in the thread pool, // so it may have not been added to active process list. // It is necessary to add it to the active list now, // to avoid it being activated immediately after it is blocked. // Activating it immediately may cause a race condition, // because it may have not been blocked completely // (namely, it may be still running). */ DaoCallServer_MarkActiveProcess( wait, 1 ); DMutex_Lock( & server->mutex ); if( timeout >= 1E-27 ){ server->timestamp.real = timeout + Dao_GetCurrentTime(); server->timestamp.imag += 1; event->expiring = server->timestamp.real; DMap_Insert( server->waitings, & server->timestamp, event ); DMap_Insert( server->pending, event, NULL ); DCondVar_Signal( & server->condv2 ); }else{ event->expiring = -1.0; DaoCallServer_AddEvent( event ); DCondVar_Signal( & server->condv ); } DMutex_Unlock( & server->mutex ); }
static void DaoMT_Critical( DaoProcess *proc, DaoValue *p[], int n ) { void *key; DNode *it; DMap *cache = (DMap*) DaoProcess_GetAuxData( proc, DaoMT_ProcMutexCache ); DaoVmCode *sect = DaoProcess_InitCodeSection( proc, 0 ); DaoRoutine *routine = proc->activeRoutine; if( sect == NULL ) return; /* Get the original routine, if this one is a specialized copy: */ while( routine->original ) routine = routine->original; /* // Use "routine + sect->c" instead of "sect" as the key for mutex, // as "sect" may be different for different copy of specialized routine. // But "sect->c" won't change after being set during compiling. */ key = routine + sect->c; if( cache == NULL ){ cache = DHash_New(0,0); /* Local cache is used to avoid extra locking; */ DaoProcess_SetAuxData( proc, DaoMT_ProcMutexCache, cache ); } it = DMap_Find( cache, key ); /* Check local cache first; */ if( it == NULL ) it = DMap_Insert( cache, key, DaoMT_GetMutex( routine, key ) ); DMutex_Lock( (DMutex*) it->value.pVoid ); DaoProcess_Execute( proc ); DMutex_Unlock( (DMutex*) it->value.pVoid ); DaoProcess_PopFrame( proc ); }
int DaoXmlParser_ParseNode( DaoXmlParser *self, DaoXmlDOM *dom, DaoXmlNode *node ) { if( DaoXmlParser_SkipWhiteSpaces( self ) ) return 1; if( self->source >= self->end ) return 1; if( *self->source != '<' ) return 1; self->source += 1; if( DaoXmlParser_SkipWhiteSpaces( self ) ) return 1; if( DaoXmlParser_ParseIdentifier( self, node->name ) ) return 1; if( DaoXmlParser_SkipWhiteSpaces( self ) ) return 1; while( self->source < self->end && isalpha( *self->source ) ){ DaoXmlParser_ParseAttribute( self, self->key, self->value ); DMap_Insert( node->attributes, self->key, self->value ); if( DaoXmlParser_SkipWhiteSpaces( self ) ) return 1; } if( self->source >= self->end ) return 1; if( *self->source == '/' ){ self->source += 1; if( self->source >= self->end ) return 1; if( *self->source != '>' ) return 1; self->source += 1; return 0; } if( *self->source != '>' ) return 1; self->source += 1; if( DaoXmlParser_ParseNodeContent( self, dom, node ) ) return 1; if( DaoXmlParser_ParseChar( self, '<' ) ) return 1; if( DaoXmlParser_ParseChar( self, '/' ) ) return 1; if( DaoXmlParser_ParseIdentifier( self, self->value ) ) return 1; if( DString_EQ( node->name, self->value ) == 0 ) return 1; if( DaoXmlParser_ParseChar( self, '>' ) ) return 1; return 0; }
static DaoComplex* DaoProcess_GetTimeData( DaoProcess *self, DaoStackFrame *frame ) { DaoComplex com = {DAO_COMPLEX,0,0,0,1,{0.0,0.0}}; DMap *mapTime = DaoProcess_GetTimeMap( self ); DNode *it = DMap_Find( mapTime, frame ); if( it == NULL ) it = DMap_Insert( mapTime, frame, & com ); return (DaoComplex*) it->value.pValue; }
void DaoxDataFrame_AddLabel( DaoxDataFrame *self, int dim, const char *lab, daoint idx ) { DString slab = DString_WrapMBS( lab ); DMap *labmap = NULL; if( dim < 0 || dim >= 3 ) return; if( idx < 0 || idx >= self->dims[dim] ) return; if( self->groups[dim] >= self->labels[dim]->size ) return; labmap = self->labels[dim]->items.pMap[ self->groups[dim] ]; if( labmap != NULL ) DMap_Insert( labmap, & slab, (void*)(size_t) idx ); }
void DaoClass_MakeInterface( DaoClass *self ) { daoint i, j; DaoType *tp; DaoRoutine *meth; DaoInterface *inter = self->inter; DMap *deftypes = DHash_New(0,0); DArray_Clear( self->inter->supers ); DMap_Clear( self->inter->methods ); if( self->parent && self->parent->type == DAO_CLASS ) DArray_Append( inter->supers, self->parent->xClass.inter ); for(i=0; i<self->cstDataName->size; ++i){ DString *name = self->cstDataName->items.pString[i]; DaoValue *value = self->constants->items.pConst[i]->value; DaoRoutine *rout = (DaoRoutine*) value; DNode *it; if( value->type != DAO_ROUTINE ) continue; if( value->xRoutine.attribs & DAO_ROUT_DECORATOR ) continue; it = MAP_Find( self->lookupTable, rout->routName ); if( it == NULL || LOOKUP_PM( it->value.pInt ) != DAO_DATA_PUBLIC ) continue; DMap_Reset( deftypes ); DMap_Insert( deftypes, rout->routHost, inter->abtype ); if( rout->overloads == NULL ){ tp = DaoType_DefineTypes( rout->routType, rout->nameSpace, deftypes ); if( tp == NULL ) continue; /* TODO: handle error; */ meth = DaoRoutine_New( rout->nameSpace, inter->abtype, 0 ); meth->attribs = rout->attribs; DString_Assign( meth->routName, rout->routName ); GC_ShiftRC( tp, meth->routType ); meth->routType = tp; DaoMethods_Insert( inter->methods, meth, meth->nameSpace, meth->routHost ); }else{ for(j=0; j<rout->overloads->routines->size; ++j){ DaoRoutine *rout2 = rout->overloads->routines->items.pRoutine[j]; if( rout2->attribs & DAO_ROUT_DECORATOR ) continue; tp = DaoType_DefineTypes( rout2->routType, rout2->nameSpace, deftypes ); if( tp == NULL ) continue; /* TODO: handle error; */ meth = DaoRoutine_New( rout2->nameSpace, inter->abtype, 0 ); meth->attribs = rout2->attribs; DString_Assign( meth->routName, rout->routName ); GC_ShiftRC( tp, meth->routType ); meth->routType = tp; DaoMethods_Insert( inter->methods, meth, meth->nameSpace, meth->routHost ); } } } DMap_Delete( deftypes ); }
int DaoValue_CompareExt( DaoValue *left, DaoValue *right, DMap *cycmap ) { DMap *input = cycmap; void *pters[2]; int res = 0; if( left == right ) return 0; if( left == NULL || right == NULL ) return left < right ? -100 : 100; if( left->type != right->type ){ double L, R; res = left->type < right->type ? -100 : 100; if( left->type < DAO_BOOLEAN || left->type > DAO_FLOAT ) return res; if( right->type < DAO_BOOLEAN || right->type > DAO_FLOAT ) return res; L = DaoValue_GetFloat( left ); R = DaoValue_GetFloat( right ); return L == R ? 0 : (L < R ? -1 : 1); } switch( left->type ){ case DAO_TUPLE : case DAO_LIST : case DAO_OBJECT : case DAO_CDATA : case DAO_CSTRUCT : pters[0] = left; pters[1] = right; if( cycmap != NULL ){ DNode *it = DMap_Find( cycmap, pters ); if( it != NULL ) return left < right ? -100 : 100; } if( cycmap == NULL ) cycmap = DHash_New(DAO_DATA_VOID2,0); DMap_Insert( cycmap, pters, NULL ); break; } switch( left->type ){ case DAO_NONE : break; case DAO_BOOLEAN : res = number_compare( left->xBoolean.value, right->xBoolean.value ); break; case DAO_INTEGER : res = number_compare( left->xInteger.value, right->xInteger.value ); break; case DAO_FLOAT : res = number_compare( left->xFloat.value, right->xFloat.value ); break; case DAO_COMPLEX : res = DaoComplex_Compare( (DaoComplex*) left, (DaoComplex*) right ); break; case DAO_STRING : res = DString_CompareUTF8( left->xString.value, right->xString.value ); break; case DAO_ENUM : res = DaoEnum_Compare( (DaoEnum*) left, (DaoEnum*) right ); break; case DAO_TUPLE : res = DaoTuple_Compare( (DaoTuple*) left, (DaoTuple*) right, cycmap ); break; case DAO_LIST : res = DaoList_Compare( (DaoList*) left, (DaoList*) right, cycmap ); break; case DAO_OBJECT : res = DaoObject_Compare( (DaoObject*)left, (DaoObject*)right, cycmap ); break; case DAO_CDATA : case DAO_CSTRUCT : res = DaoCstruct_Compare( (DaoCstruct*)left, (DaoCstruct*)right, cycmap ); break; case DAO_TYPE : res = DaoType_Compare( (DaoType*) left, (DaoType*) right ); break; #ifdef DAO_WITH_NUMARRAY case DAO_ARRAY : res = DaoArray_Compare( (DaoArray*) left, (DaoArray*) right ); break; #endif default: res = left < right ? -100 : 100; break; /* Needed for map; */ } if( cycmap != input ) DMap_Delete( cycmap ); return res; }
static DMutex* DaoMT_GetMutex( DaoRoutine *routine, void *key ) { DNode *it; DMap *mutexes; DMutex *mutex = NULL; DMutex_Lock( & mainVmSpace->miscMutex ); it = DMap_Find( routine->body->aux, DaoMT_RoutMutexSet ); if( it == NULL ) it = DMap_Insert( routine->body->aux, DaoMT_RoutMutexSet, DHash_New(0,0) ); mutexes = (DMap*) it->value.pVoid; it = DMap_Find( mutexes, key ); if( it == NULL ){ mutex = (DMutex*) dao_calloc(1,sizeof(DMutex)); DMutex_Init( mutex ); DMap_Insert( mutexes, key, mutex ); }else{ mutex = (DMutex*) it->value.pVoid; } DMutex_Unlock( & mainVmSpace->miscMutex ); return mutex; }
static void DaoInterface_TempBind( DaoInterface *self, DaoType *type, DMap *binds ) { daoint i, N = self->supers->size; void *pvoid[2]; pvoid[0] = type; pvoid[1] = self->abtype; if( DMap_Find( binds, pvoid ) ) return; DMap_Insert( binds, pvoid, NULL ); for(i=0; i<N; i++){ DaoInterface *super = (DaoInterface*) self->supers->items.pValue[i]; DaoInterface_TempBind( super, type, binds ); } }
DaoRoutine* DaoInterface_BindTo( DaoInterface *self, DaoType *type, DMap *binds ) { DNode *it; DMap *newbinds = NULL; DList *methods; DaoRoutine *incompatible; void *pvoid[2]; daoint i, n; if( self->abtype->kernel->SetupMethods ){ DaoTypeKernel *kernel = self->abtype->kernel; kernel->SetupMethods( kernel->nspace, self->abtype->core ); } /* XXX locking */ if( type->interfaces == NULL ){ type->interfaces = DHash_New( DAO_DATA_VALUE, DAO_DATA_VALUE ); } pvoid[0] = type; pvoid[1] = self->abtype; if( (it = DMap_Find( type->interfaces, self )) ) return it->value.pRoutine; if( binds && DMap_Find( binds, pvoid ) ) return NULL; if( binds ==NULL ) newbinds = binds = DHash_New( DAO_DATA_VOID2, 0 ); DaoInterface_TempBind( self, type, binds ); methods = DList_New(0); DMap_SortMethods( self->methods, methods ); incompatible = DaoInterface_CheckBind( methods, type, binds ); DList_Delete( methods ); if( newbinds ) DMap_Delete( newbinds ); DMap_Insert( type->interfaces, self, incompatible ); if( incompatible ) return incompatible; for(i=0,n=self->bases->size; i<n; i++){ DaoInterface *base = (DaoInterface*) self->bases->items.pValue[i]; if( DMap_Find( type->interfaces, base ) ) continue; DMap_Insert( type->interfaces, base, NULL ); } return NULL; }
static void DaoxProfiler_Update( DaoxProfiler *self, DaoStackFrame *frame, double time ) { DaoComplex com = {DAO_COMPLEX,0,0,0,1,{0.0,0.0}}; DaoRoutine *caller = frame->prev ? frame->prev->routine : NULL; DaoRoutine *callee = frame->routine; DNode *it, *it2; if( frame->returning == 0xffff ) caller = NULL; while( caller && caller->original ) caller = caller->original; while( callee && callee->original ) callee = callee->original; DMutex_Lock( & self->mutex ); { it = DMap_Find( self->profile, callee ); if( it == NULL ) it = DMap_Insert( self->profile, callee, self->one ); it2 = DMap_Find( it->value.pMap, caller ); if( it2 == NULL ) it2 = DMap_Insert( it->value.pMap, caller, & com ); it2->value.pValue->xComplex.value.real += time; it2->value.pValue->xComplex.value.imag += 1; } DMutex_Unlock( & self->mutex ); }
DaoXmlParser* DaoXmlParser_New() { DaoXmlParser *self = (DaoXmlParser*) dao_calloc( 1, sizeof(DaoXmlParser) ); self->key = DString_New(); self->value = DString_New(); self->escape = DString_New(); self->escapes = DHash_New( DAO_DATA_STRING, DAO_DATA_STRING ); DString_SetChars( self->key, "lt" ); DString_SetChars( self->value, "<" ); DMap_Insert( self->escapes, self->key, self->value ); DString_SetChars( self->key, "gt" ); DString_SetChars( self->value, ">" ); DMap_Insert( self->escapes, self->key, self->value ); DString_SetChars( self->key, "amp" ); DString_SetChars( self->value, "&" ); DMap_Insert( self->escapes, self->key, self->value ); DString_SetChars( self->key, "apos" ); DString_SetChars( self->value, "'" ); DMap_Insert( self->escapes, self->key, self->value ); DString_SetChars( self->key, "quot" ); DString_SetChars( self->value, "\"" ); DMap_Insert( self->escapes, self->key, self->value ); return self; }
void DaoProcess_MarkActiveTasklet( DaoProcess *self, int active ) { DaoTaskletServer *server = DaoTaskletServer_TryInit( self->vmSpace ); if( self->active == active ) return; DMutex_Lock( & server->mutex ); if( active ){ DMap_Insert( server->active, self, NULL ); self->active = 1; }else{ DMap_Erase( server->active, self ); self->active = 0; } DMutex_Unlock( & server->mutex ); }
void DaoCallServer_MarkActiveProcess( DaoProcess *process, int active ) { DaoCallServer *server = daoCallServer; if( daoCallServer == NULL ) return; if( process->active == active ) return; DMutex_Lock( & server->mutex ); if( active ){ DMap_Insert( server->active, process, NULL ); process->active = 1; }else{ DMap_Erase( server->active, process ); process->active = 0; } DMutex_Unlock( & server->mutex ); }
void DaoObject_Print( DaoValue *self, DaoStream *stream, DMap *cycmap, DaoProcess *proc ) { int ec = 0; char buf[50]; DMap *inmap = cycmap; DaoObject *object = (DaoObject*) self; DaoValue *params[2]; DaoRoutine *meth; sprintf( buf, "[%p]", object ); if( self == object->defClass->objType->value ){ DaoStream_WriteString( stream, object->defClass->className ); DaoStream_WriteChars( stream, "[null]" ); return; } if( cycmap != NULL && DMap_Find( cycmap, object ) != NULL ){ DaoStream_WriteString( stream, object->defClass->className ); DaoStream_WriteChars( stream, buf ); return; } if( cycmap == NULL ) cycmap = DHash_New(0,0); DMap_Insert( cycmap, self, self ); DaoValue_Clear( & proc->stackValues[0] ); params[0] = (DaoValue*) dao_type_string; params[1] = (DaoValue*) stream; meth = DaoClass_FindMethod( object->defClass, "(string)", NULL ); if( meth ){ ec = DaoProcess_Call( proc, meth, self, params, 2 ); if( ec ) ec = DaoProcess_Call( proc, meth, self, params, 1 ); }else{ meth = DaoClass_FindMethod( object->defClass, "serialize", NULL ); if( meth ) ec = DaoProcess_Call( proc, meth, self, NULL, 0 ); } if( ec ){ DaoProcess_RaiseException( proc, daoExceptionNames[ec], proc->string->chars, NULL ); }else if( meth && proc->stackValues[0] ){ DaoValue_Print( proc->stackValues[0], stream, cycmap, proc ); }else{ DaoStream_WriteString( stream, object->defClass->className ); DaoStream_WriteChars( stream, buf ); } if( inmap == NULL ) DMap_Delete( cycmap ); }
void DaoCallServer_AddTask( DThreadTask func, void *param, int now ) { int scheduled = 0; DaoCallServer *server = DaoCallServer_TryInit( mainVmSpace ); DMutex_Lock( & server->mutex ); if( server->idle > server->parameters->size || now == 0 ){ scheduled = 1; DList_Append( server->functions, func ); DList_Append( server->parameters, param ); DMap_Insert( server->pending, param, NULL ); DCondVar_Signal( & server->condv ); } DMutex_Unlock( & server->mutex ); if( scheduled ){ if( now == 0 ) DaoCallServer_TryAddThread( NULL, NULL, server->parameters->size ); }else{ DaoCallServer_AddThread( func, param ); } }
static void DaoCinValue_Print( DaoValue *self, DaoStream *stream, DMap *cycmap, DaoProcess *proc ) { int ec = 0; char buf[50]; DaoRoutine *meth; DaoValue *args[2]; DaoType *type = self->xCinValue.cintype->vatype; DMap *inmap = cycmap; if( cycmap != NULL && DMap_Find( cycmap, self ) != NULL ){ sprintf( buf, "[%p]", self ); DaoStream_WriteString( stream, type->name ); DaoStream_WriteChars( stream, buf ); return; } if( cycmap == NULL ) cycmap = DHash_New(0,0); DMap_Insert( cycmap, self, self ); args[0] = (DaoValue*) proc->vmSpace->typeString; args[1] = (DaoValue*) stream; meth = DaoType_FindFunctionChars( type, "(string)" ); if( meth ){ ec = DaoProcess_Call( proc, meth, self, args, 2 ); if( ec ) ec = DaoProcess_Call( proc, meth, self, args, 1 ); }else{ meth = DaoType_FindFunctionChars( type, "serialize" ); if( meth ) ec = DaoProcess_Call( proc, meth, self, NULL, 0 ); } if( meth == NULL ){ DaoValue_Print( self->xCinValue.value, stream, cycmap, proc ); }else if( ec ){ DaoProcess_RaiseException( proc, daoExceptionNames[ec], proc->string->chars, NULL ); }else if( meth && proc->stackValues[0] ){ DaoValue_Print( proc->stackValues[0], stream, cycmap, proc ); }else{ DaoStream_WriteString( stream, type->name ); DaoStream_WriteChars( stream, buf ); } if( inmap == NULL ) DMap_Delete( cycmap ); }
void DaoVmSpace_AddTaskletJob( DaoVmSpace *self, DThreadTask func, void *param, void *proc ) { int scheduled = 0; DaoTaskletServer *server = DaoTaskletServer_TryInit( self ); DMutex_Lock( & server->mutex ); if( server->vacant > server->parameters->size || proc == NULL ){ scheduled = 1; DList_Append( server->functions, func ); DList_Append( server->parameters, param ); DList_Append( server->owners, proc ); DMap_Insert( server->pending, param, NULL ); DCondVar_Signal( & server->condv ); } DMutex_Unlock( & server->mutex ); if( scheduled ){ if( proc == NULL ){ DaoVmSpace_TryAddTaskletThread( self, NULL, NULL, server->parameters->size ); } }else{ DaoVmSpace_AddTaskletThread( self, func, param, proc ); } }
static void DaoClass_SetupMethodFields( DaoClass *self, DaoMethodFields *mf ) { DaoValue *cst; DMap *overloads = DMap_New(D_STRING,0); DNode *it, *search; daoint i, id, pm, pm2; for(i=0; i<mf->names->size; ++i){ DString *name = mf->names->items.pString[i]; it = DMap_Find( self->lookupTable, name ); if( it == NULL ) continue; if( LOOKUP_ST( it->value.pInt ) != DAO_CLASS_CONSTANT ) continue; id = LOOKUP_ID( it->value.pInt ); DMap_Insert( overloads, name, self->constants->items.pConst[id]->value ); } for(i=0; i<mf->names->size; ++i){ DString *name = mf->names->items.pString[i]; it = DMap_Find( self->lookupTable, name ); if( it == NULL ) continue; if( LOOKUP_ST( it->value.pInt ) != DAO_CLASS_CONSTANT ) continue; cst = mf->routines->items.pValue[i]; search = DMap_Find( overloads, name ); if( cst == search->value.pValue ) continue; pm = LOOKUP_PM( it->value.pInt ); pm2 = mf->perms->items.pInt[i]; if( pm2 > pm ) pm = pm2; /* // Add again the overloaded methods, so that a new overloading structure // will be created for the host class. This is necessary to avoid messing // the function calls in the methods of the mixins. */ DaoClass_AddConst( self, name, cst, pm ); } DMap_Delete( overloads ); }
DaoxImage* DaoxResource_LoadImage( DaoxResource *self, DString *fname, DString *path ) { DaoxImage *image = NULL; DString *file = DString_Copy( fname ); DString *source = DString_New(); DString_Change( file, "\\\\", "/", 0 ); DString_Change( file, "\\", "/", 0 ); if( DaoxResource_SearchFile( self, file, path ) ){ DNode *it = DMap_Find( self->images, file ); if( it != NULL ){ image = (DaoxImage*) it->value.pValue; }else if( DaoxResource_ReadFile( self, file, source ) ){ image = DaoxImage_New(); DaoxImage_Decode( image, source ); DMap_Insert( self->images, file, image ); } } DString_Delete( source ); DString_Delete( file ); return image; }
static void DaoCallThread_Run( DaoCallThread *self ) { DaoCallServer *server = daoCallServer; double wt = 0.001; daoint i, count, timeout; self->thdData = DThread_GetSpecific(); if( self->taskFunc ){ self->taskFunc( self->taskParam ); self->taskOwner = NULL; } while( server->vmspace->stopit == 0 ){ DaoProcess *process = NULL; DaoFuture *future = NULL; DThreadTask function = NULL; void *parameter = NULL; if( self->thdData != NULL ) self->thdData->state = 0; DMutex_Lock( & server->mutex ); server->idle += 1; server->vacant += self->taskOwner == NULL; while( server->pending->size == (server->events2->size + server->waitings->size) ){ //printf( "%p %i %i %i %i\n", self, server->events->size, server->pending->size, server->events2->size, server->waitings->size ); if( server->vmspace->stopit ) break; if( server->finishing && server->vacant == server->total ){ if( (server->events2->size + server->waitings->size) == 0 ) break; } wt = 0.01*(server->idle == server->total) + 0.001; timeout = DCondVar_TimedWait( & server->condv, & server->mutex, wt ); } for(i=0; i<server->parameters->size; ++i){ void *param = server->parameters->items.pVoid[i]; if( DMap_Find( server->active, param ) ) continue; DMap_Insert( server->active, param, NULL ); self->taskOwner = server->owners->items.pVoid[i]; function = (DThreadTask) server->functions->items.pVoid[i]; parameter = param; DList_Erase( server->functions, i, 1 ); DList_Erase( server->parameters, i, 1 ); DList_Erase( server->owners, i, 1 ); DMap_Erase( server->pending, parameter ); server->idle -= 1; server->vacant -= 1; break; } DMutex_Unlock( & server->mutex ); if( server->vmspace->stopit ) break; if( function ){ (*function)( parameter ); self->taskOwner = NULL; DMutex_Lock( & server->mutex ); DMap_Erase( server->active, parameter ); DMutex_Unlock( & server->mutex ); continue; } if( server->pending->size == 0 && server->finishing && server->vacant == server->total ) break; DMutex_Lock( & server->mutex ); server->idle -= 1; server->vacant -= self->taskOwner == NULL; future = DaoCallServer_GetNextFuture(); DMutex_Unlock( & server->mutex ); if( future == NULL ) continue; process = future->process; if( process == NULL ){ GC_DecRC( future ); continue; } count = process->exceptions->size; future->state = DAO_CALL_RUNNING; DaoProcess_InterceptReturnValue( process ); DaoProcess_Start( process ); if( process->exceptions->size > count ) DaoProcess_PrintException( process, NULL, 1 ); if( process->status <= DAO_PROCESS_ABORTED ) self->taskOwner = NULL; if( future->actor ){ int erase = 1; DMutex_Lock( & server->mutex ); if( future->actor->rootObject->isAsync ){ erase = process->status == DAO_PROCESS_FINISHED; } if( erase ) DMap_Erase( server->active, future->actor->rootObject ); DMutex_Unlock( & server->mutex ); } DMutex_Lock( & server->mutex ); DMap_Erase( server->active, process ); process->active = 0; DMutex_Unlock( & server->mutex ); DaoProcess_ReturnFutureValue( process, future ); if( future->state == DAO_CALL_FINISHED ) DaoFuture_ActivateEvent( future ); GC_DecRC( future ); } DMutex_Lock( & server->mutex ); server->stopped += 1; DMutex_Unlock( & server->mutex ); }
static DaoFuture* DaoCallServer_GetNextFuture() { DaoCallServer *server = daoCallServer; DaoFuture *first, *future, *precond; DList *events = server->events; DMap *pending = server->pending; DMap *active = server->active; DNode *it; daoint i, j; for(i=0; i<events->size; i++){ DaoTaskEvent *event = (DaoTaskEvent*) events->items.pVoid[i]; DaoFuture *future = event->future; DaoObject *actor = future->actor; DaoChannel *channel = event->channel; DaoChannel *closed = NULL; DaoChannel *chselect = NULL; DaoFuture *futselect = NULL; DaoValue *selected = NULL; DaoValue *message = NULL; int type = event->type; if( event->state == DAO_EVENT_WAIT && future->precond != NULL ){ if( future->precond->state != DAO_CALL_FINISHED ) goto MoveToWaiting; } switch( event->type ){ case DAO_EVENT_WAIT_SENDING : if( channel->buffer->size >= channel->cap ){ if( event->state == DAO_EVENT_WAIT ){ DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_RECEIVING ); DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_SELECT ); goto MoveToWaiting; } } event->type = DAO_EVENT_RESUME_TASKLET; break; case DAO_EVENT_WAIT_RECEIVING : if( channel->buffer->size == 0 ){ if( channel->cap > 0 && event->state == DAO_EVENT_WAIT ){ DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_SENDING ); goto MoveToWaiting; } message = dao_none_value; }else{ message = channel->buffer->items.pValue[0]; } GC_Assign( & event->message, message ); event->auxiliary = channel->cap <= 0 && channel->buffer->size == 0; event->type = DAO_EVENT_RESUME_TASKLET; DList_PopFront( channel->buffer ); if( channel->buffer->size < channel->cap ) DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_SENDING ); if( channel->buffer->size ) DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_RECEIVING ); break; case DAO_EVENT_WAIT_SELECT : message = dao_none_value; for(it=DaoMap_First(event->selects); it; it=DaoMap_Next(event->selects,it)){ if( DaoValue_CheckCtype( it->key.pValue, dao_type_channel ) ){ DaoChannel *chan = (DaoChannel*) it->key.pValue; if( chan->buffer->size > 0 ){ chselect = chan; selected = it->key.pValue; message = chan->buffer->items.pValue[0]; closed = NULL; break; }else if( chan->cap == 0 ){ closed = chan; } }else{ DaoFuture *fut = (DaoFuture*) it->key.pValue; if( fut->state == DAO_CALL_FINISHED ){ futselect = fut; selected = it->key.pValue; message = fut->value; break; } } } if( selected == NULL ) selected = (DaoValue*) closed; if( event->state == DAO_EVENT_WAIT && event->selects->value->size ){ if( selected == NULL ) goto MoveToWaiting; } GC_Assign( & event->message, message ); GC_Assign( & event->selected, selected ); event->auxiliary = event->selects->value->size == 0; event->type = DAO_EVENT_RESUME_TASKLET; /* change status to not finished: */ if( chselect != NULL || futselect != NULL ) event->auxiliary = 0; if( chselect ){ DList_PopFront( chselect->buffer ); if( chselect->buffer->size < chselect->cap ) DaoChannel_ActivateEvent( chselect, DAO_EVENT_WAIT_SENDING ); if( chselect->buffer->size ) DaoChannel_ActivateEvent( chselect, DAO_EVENT_WAIT_SELECT ); } if( futselect != NULL || closed != NULL ){ void *key = futselect ? (void*)futselect : (void*)closed; DMap_Erase( event->selects->value, key ); } break; default: break; } if( actor ){ DNode *it = DMap_Find( active, actor->rootObject ); if( actor->rootObject->isAsync ){ if( it && it->value.pVoid != (void*) future ) continue; }else if( it ){ continue; } } if( future->process && DMap_Find( active, future->process ) ) continue; DList_Erase( events, i, 1 ); DMap_Erase( pending, event ); if( actor ){ void *value = actor->rootObject->isAsync ? future : NULL; DMap_Insert( active, actor->rootObject, value ); } if( future->process ){ DMap_Insert( active, future->process, NULL ); future->process->active = 1; } /* // DaoValue_Move() should be used instead of GC_Assign() for thread safety. // Because using GC_Assign() here, may caused "future->message" of primitive // type being deleted, right after DaoFuture_GetGCFields() has retrieved it // for GC scanning. */ DaoValue_Move( event->message, & future->message, NULL ); DaoValue_Move( event->selected, & future->selected, NULL ); future->aux1 = event->auxiliary; future->timeout = event->timeout; GC_IncRC( future ); /* To be decreased at the end of tasklet; */ DaoCallServer_CacheEvent( event ); return future; MoveToWaiting: if( event->expiring >= 0.0 && event->expiring < MIN_TIME ) continue; if( event->expiring >= MIN_TIME ){ dao_complex com = {0.0,0.0}; com.real = event->expiring; DMap_Insert( server->waitings, & com, event ); DCondVar_Signal( & server->condv2 ); }else{ DList_Append( server->events2, event ); } DList_Erase( server->events, i, 1 ); i -= 1; } return NULL; }
static void DaoCallServer_AddEvent( DaoTaskEvent *event ) { DaoCallServer *server = daoCallServer; DList_Append( server->events, event ); DMap_Insert( server->pending, event, NULL ); }
static void DaoTaskletServer_AddEvent( DaoTaskletServer *self, DaoTaskletEvent *event ) { DList_Append( self->events, event ); DMap_Insert( self->pending, event, NULL ); }
/* // Note: reference count is handled for "value2"! // // Item of list/tuple etc. can be directly passed as parameter "value2", // to avoid creating unnecessary intermediate objects. */ static int DaoParser_Deserialize( DaoParser *self, int start, int end, DaoValue **value2, DArray *types, DaoNamespace *ns, DaoProcess *proc, DMap *omap ) { DaoToken **tokens = self->tokens->items.pToken; DaoType *it1 = NULL, *it2 = NULL, *type = NULL; DaoValue *value = *value2; DaoValue *tmp = NULL; DaoValue *tmp2 = NULL; DaoObject *object; DaoCdata *cdata; DaoArray *array; DaoTuple *tuple; DaoList *list; DaoMap *map; DArray *dims; DNode *node; void *key = NULL; char *str; int i, j, k, n; int minus = 0; int next = start + 1; int tok2 = start < end ? tokens[start+1]->type : 0; int maybetype = tok2 == DTOK_COLON2 || tok2 == DTOK_LT || tok2 == DTOK_LCB; if( tokens[start]->type == DTOK_AT && tok2 == DTOK_LCB ){ int rb = DaoParser_FindPairToken( self, DTOK_LCB, DTOK_RCB, start, end ); if( rb < 0 ) return next; sscanf( tokens[start+2]->string.mbs, "%p", & key ); node = DMap_Find( omap, key ); if( node ) DaoValue_Copy( node->value.pValue, value2 ); return rb + 1; } if( tokens[start]->name == DTOK_ID_SYMBOL ){ DString *mbs = DString_New(1); while( tokens[start]->name == DTOK_ID_SYMBOL ){ DString_Append( mbs, & tokens[start]->string ); start += 1; } type = DaoNamespace_MakeType( ns, mbs->mbs, DAO_ENUM, NULL, NULL, 0 ); DString_Delete( mbs ); if( type == NULL ) return start; if( tokens[start]->name != DTOK_LCB ) return start; end = DaoParser_FindPairToken( self, DTOK_LCB, DTOK_RCB, start, end ); if( end < 0 ) return start; next = end + 1; start += 1; end -= 1; }else if( tokens[start]->type == DTOK_IDENTIFIER && maybetype ){ type = DaoParser_ParseType( self, start, end, & start, NULL ); if( type == NULL ) return next; if( tokens[start]->name != DTOK_LCB ) return start; end = DaoParser_FindPairToken( self, DTOK_LCB, DTOK_RCB, start, end ); if( end < 0 ) return start; next = end + 1; start += 1; end -= 1; } if( type == NULL ){ type = types->items.pType[0]; if( type && type->tid >= DAO_ARRAY ){ if( tokens[start]->name != DTOK_LCB ) return start; end = DaoParser_FindPairToken( self, DTOK_LCB, DTOK_RCB, start, end ); if( end < 0 ) return start; next = end + 1; start += 1; end -= 1; } } if( type == NULL ) return next; DaoValue_Copy( type->value, value2 ); if( start > end ) return next; if( tokens[start]->name == DTOK_SUB ){ minus = 1; start += 1; if( start > end ) return next; } if( type->nested && type->nested->size >0 ) it1 = type->nested->items.pType[0]; if( type->nested && type->nested->size >1 ) it2 = type->nested->items.pType[1]; if( tokens[start]->name == DTOK_LB ){ int rb = DaoParser_FindPairToken( self, DTOK_LB, DTOK_RB, start, end ); if( rb < 0 ) return next; sscanf( tokens[start+1]->string.mbs, "%p", & key ); DMap_Insert( omap, key, *value2 ); start = rb + 1; } str = tokens[start]->string.mbs; #if 0 printf( "type: %s %s\n", type->name->mbs, str ); for(i=start; i<=end; i++) printf( "%s ", tokens[i]->string.mbs ); printf( "\n" ); #endif value = *value2; switch( type->tid ){ case DAO_NONE : break; case DAO_INTEGER : value->xInteger.value = DaoDecodeInteger( str ); if( minus ) value->xInteger.value = - value->xInteger.value; break; case DAO_FLOAT : value->xFloat.value = DaoDecodeDouble( str ); if( minus ) value->xFloat.value = - value->xFloat.value; break; case DAO_DOUBLE : value->xDouble.value = DaoDecodeDouble( str ); if( minus ) value->xDouble.value = - value->xDouble.value; break; case DAO_COMPLEX : value->xComplex.value.real = DaoDecodeDouble( str ); if( minus ) value->xComplex.value.real = - value->xComplex.value.real; if( start + 1 > end ) return start+1; minus = 0; if( tokens[start + 1]->name == DTOK_SUB ){ minus = 1; start += 1; if( start + 1 > end ) return start+1; } value->xComplex.value.imag = DaoDecodeDouble( tokens[start+1]->string.mbs ); if( minus ) value->xComplex.value.imag = - value->xComplex.value.imag; next = start + 2; break; #ifdef DAO_WITH_LONGINT case DAO_LONG : value->xLong.value->base = DaoDecodeInteger( str ); start += 1; if( tokens[start]->name == DTOK_ADD ){ value->xLong.value->sign = 1; start += 1; }else if( tokens[start]->name == DTOK_SUB ){ value->xLong.value->sign = -1; start += 1; } for(i=start; i<=end; i++){ if( tokens[i]->name == DTOK_COMMA ) continue; DLong_PushBack( value->xLong.value, DaoDecodeInteger( tokens[i]->string.mbs ) ); } break; #endif case DAO_STRING : n = tokens[start]->string.size - 1; for(i=1; i<n; i++){ char c1 = str[i]; char c2 = str[i+1]; if( c1 < 'A' || c1 > 'P' ) continue; DString_AppendChar( value->xString.data, (char)((c1-'A')*16 + (c2-'A')) ); i += 1; } if( str[0] == '\"' ) DString_ToWCS( value->xString.data ); break; case DAO_ENUM : value->xEnum.value = DaoDecodeInteger( str ); break; case DAO_ARRAY : #ifdef DAO_WITH_NUMARRAY if( tokens[start]->name != DTOK_LSB ) return next; k = DaoParser_FindPairToken( self, DTOK_LSB, DTOK_RSB, start, end ); if( k < 0 ) return next; n = 1; for(i=start+1; i<k; i++){ if( tokens[i]->name == DTOK_COMMA ) continue; n *= strtol( tokens[i]->string.mbs, 0, 0 ); } if( n < 0 ) return next; if( it1 == NULL || it1->tid == 0 || it1->tid > DAO_COMPLEX ) return next; array = & value->xArray; dims = DArray_New(0); for(i=start+1; i<k; i++){ if( tokens[i]->name == DTOK_COMMA ) continue; j = strtol( tokens[i]->string.mbs, 0, 0 ); DArray_Append( dims, (size_t) j ); } n = dims->size; DaoArray_ResizeArray( array, dims->items.pInt, n ); DArray_PushFront( types, it1 ); DArray_Delete( dims ); n = 0; for(i=k+1; i<=end; i++){ j = i + 1; while( j <= end && tokens[j]->name != DTOK_COMMA ) j += 1; DaoParser_Deserialize( self, i, j-1, & tmp, types, ns, proc, omap ); switch( it1->tid ){ case DAO_INTEGER : array->data.i[n] = tmp->xInteger.value; break; case DAO_FLOAT : array->data.f[n] = tmp->xFloat.value; break; case DAO_DOUBLE : array->data.d[n] = tmp->xDouble.value; break; } i = j; n += 1; } DArray_PopFront( types ); #endif break; case DAO_LIST : list = & value->xList; DArray_PushFront( types, it1 ); n = 0; for(i=start; i<=end; i++){ if( tokens[i]->name == DTOK_COMMA ) continue; DArray_Append( & list->items, NULL ); k = DaoParser_Deserialize( self, i, end, list->items.items.pValue + n, types, ns, proc, omap ); i = k - 1; n += 1; } DArray_PopFront( types ); break; case DAO_MAP : map = & value->xMap; n = 0; for(i=start; i<=end; i++){ if( tokens[i]->name == DTOK_COMMA ) continue; DaoValue_Clear( & tmp ); DaoValue_Clear( & tmp2 ); DArray_PushFront( types, it1 ); i = DaoParser_Deserialize( self, i, end, &tmp, types, ns, proc, omap ); DArray_PopFront( types ); if( tokens[i]->name == DTOK_COMMA ) continue; if( map->items->size == 0 ){ if( tokens[i]->name == DTOK_COLON ){ DMap_Delete( map->items ); map->items = DHash_New( D_VALUE, D_VALUE ); } } if( tokens[i]->name == DTOK_COLON || tokens[i]->name == DTOK_FIELD ) i += 1; DArray_PushFront( types, it2 ); i = DaoParser_Deserialize( self, i, end, &tmp2, types, ns, proc, omap ); DArray_PopFront( types ); node = DMap_Insert( map->items, (void*) tmp, (void*) tmp2 ); i -= 1; n += 1; } break; case DAO_TUPLE : tuple = & value->xTuple; n = 0; for(i=start; i<=end; i++){ if( tokens[i]->name == DTOK_COMMA ) continue; it1 = NULL; if( type->nested && type->nested->size > n ){ it1 = type->nested->items.pType[n]; if( it1 && it1->tid == DAO_PAR_NAMED ) it1 = & it1->aux->xType; } DArray_PushFront( types, it1 ); i = DaoParser_Deserialize( self, i, end, tuple->items + n, types, ns, proc, omap ); DArray_PopFront( types ); i -= 1; n += 1; } break; case DAO_OBJECT : DArray_PushFront( types, NULL ); DaoParser_Deserialize( self, start, end, & tmp, types, ns, proc, omap ); DArray_PopFront( types ); if( tmp == NULL ) break; object = DaoClass_MakeObject( & type->aux->xClass, tmp, proc ); if( object ) DaoValue_Copy( (DaoValue*) object, value2 ); break; case DAO_CDATA : case DAO_CSTRUCT : DArray_PushFront( types, NULL ); DaoParser_Deserialize( self, start, end, & tmp, types, ns, proc, omap ); DArray_PopFront( types ); if( tmp == NULL ) break; cdata = DaoCdata_MakeObject( & type->aux->xCdata, tmp, proc ); if( cdata ) DaoValue_Copy( (DaoValue*) cdata, value2 ); break; } DaoValue_Clear( & tmp ); DaoValue_Clear( & tmp2 ); return next; }
void DaoProfiler_Report( DaoProfiler *self0, DaoStream *stream ) { DaoComplex com = {DAO_COMPLEX,0,0,0,1,{0.0,0.0}}; DaoxProfiler *self = (DaoxProfiler*) self0; DMap *summary = DMap_New( DAO_DATA_VALUE, 0 ); DMap *summary2 = DMap_New( DAO_DATA_VALUE, 0 ); DString *name1 = DString_New(); DString *name2 = DString_New(); DNode *it, *it2; int count, max = 20; char buf1[32]; char buf2[24]; char buf[120]; for(it=DMap_First(self->profile); it; it=DMap_Next(self->profile,it)){ DaoRoutine *callee = (DaoRoutine*) it->key.pValue; com.value = DaoProfiler_Sum( it->value.pMap ); com.value.real = - com.value.real; com.value.imag = - com.value.imag; DMap_Insert( summary, & com, it ); } DaoStream_WriteChars( stream, "\n" ); DaoStream_WriteChars( stream, delimiter ); DaoStream_WriteChars( stream, delimiter2 ); snprintf( buf, sizeof(buf), header_format, "Routine", "#Calls", "CPU Time" ); DaoStream_WriteChars( stream, buf ); DaoStream_WriteChars( stream, delimiter2 ); for(count=max,it=DMap_First(summary); it; it=DMap_Next(summary,it),--count){ DNode *it2 = (DNode*) it->value.pVoid; dao_complex data = it->key.pValue->xComplex.value; DaoRoutine *callee = (DaoRoutine*) it2->key.pValue; DaoRoutine_MakeName( callee, name1, 28, 10, 2 ); snprintf( buf, sizeof(buf), row_format, name1->chars, (int) -data.imag, -data.real ); DaoStream_WriteChars( stream, buf ); if( count == 0 ) break; } DaoStream_WriteChars( stream, "\n" ); DaoStream_WriteChars( stream, delimiter3 ); snprintf( buf, sizeof(buf), header_format2, "Routine", "Caller", "#Calls", "CPU Time" ); DaoStream_WriteChars( stream, buf ); DaoStream_WriteChars( stream, delimiter3 ); for(count=max,it=DMap_First(summary); it; it=DMap_Next(summary,it),--count){ DNode *it2 = (DNode*) it->value.pVoid; DaoRoutine *callee = (DaoRoutine*) it2->key.pValue; DMap *profile = it2->value.pMap; DaoRoutine_MakeName( callee, name1, 30, 0, 0 ); DMap_Reset( summary2 ); for(it2=DMap_First(profile); it2; it2=DMap_Next(profile,it2)){ DaoRoutine *caller = (DaoRoutine*) it2->key.pValue; DaoComplex *data = (DaoComplex*) it2->value.pValue; com.value.real = - data->value.real; com.value.imag = - data->value.imag; DMap_Insert( summary2, & com, caller ); } for(it2=DMap_First(summary2); it2; it2=DMap_Next(summary2,it2)){ DaoRoutine *caller = (DaoRoutine*) it2->value.pValue; dao_complex data = it2->key.pValue->xComplex.value; DString_Reset( name2, 0 ); if( caller ) DaoRoutine_MakeName( caller, name2, 22, 0, 0 ); snprintf( buf, sizeof(buf), row_format2, name1->chars, name2->chars, (int) -data.imag, -data.real ); DaoStream_WriteChars( stream, buf ); DString_Reset( name1, 0 ); } if( count == 0 ) break; } DString_Delete( name1 ); DString_Delete( name2 ); }