示例#1
0
Sint deletememorymap(char *file,Uint line,void *mappedfile)
{
  Filedesctype fd;

  if(mappedfile == NULL)
  {
    ERROR2("%s: l. %ld: deletememorymap: mappedfile is NULL",
             file,(Showsint) line);
    return -1;
  }
  for(fd=0; fd<MAXMAPPEDFILES; fd++)
  {
    if(memoryptr[fd] == mappedfile)
    {
      break;
    }
  }
  if(fd == MAXMAPPEDFILES)
  {
    ERROR2("%s: l. %ld: deletememorymap: cannot find filedescriptor for given address",
           file,(Showsint) line);
    return -2;
  }
  if(munmap(memoryptr[fd],(size_t) mappedbytes[fd]) != 0)
  {
    ERROR4("%s: l. %ld: deletememorymap: munmap failed:"
           " mapped in file \"%s\",line %lu",
            file,
            (Showsint) line,
            filemapped[fd],
            (Showuint) linemapped[fd]);
    return -3;
  }
  DEBUG4(2,"# file \"%s\", line %ld: deletememorymap:fd=%ld (%lu) bytes:\n",
          file,
          (Showsint) line,
          (Showsint) fd,
          (Showuint) mappedbytes[fd]);
  DEBUG2(2,"# mapped in file \"%s\", line %lu\n",filemapped[fd],
                                                 (Showuint) linemapped[fd]);
  memoryptr[fd] = NULL;
  mmsubtractspace(mappedbytes[fd]);
  mappedbytes[fd] = 0;
  if(close(fd) != 0)
  {
    ERROR1("cannot close file \"%s\"",filemapped[fd]);
    return -4;
  }
  return 0;
}
CMProperty CM_FIXEDARGS CMRegisterProperty(CMContainer targetContainer,
																					 CMconst_CMGlobalName name)
{
	TOCObjectPtr	p;
	GlobalNamePtr g;
	ContainerPtr 	container = (ContainerPtr)targetContainer;
	
	NOPifNotInitialized(NULL);												/* NOP if not initialized!					*/

	g = cmLookupGlobalName(container->globalNameTable, (CM_UCHAR *)name);
	
	if (!SessionSuccess) {
		ERROR2(CM_err_GloblaNameError, name, CONTAINERNAME);
		return (NULL);
	}
	
	if (g && g->theValue) {
		p = g->theValue->theValueHdr->theProperty->theObject;
		if ((p->objectFlags & PropertyObject) == 0) {
			ERROR4(CM_err_MultTypeProp, "type", name, CONTAINERNAME,
						 (p->objectFlags & TypeObject) ? "type" : "object");
			p = NULL;
		} else
			++p->useCount;																/* bump this object's use count			*/
	} else {
		p = cmDefineGlobalNameObject(container, container->nextUserObjectID, CM_StdObjID_GlobalPropName,
																 CM_StdObjID_7BitASCII, (CM_UCHAR *)name,
																 container->generation, 0, PropertyObject);
		if (p) {
			p->useCount = 1;															/* initial use of this object				*/
			IncrementObjectID(container->nextUserObjectID);
		}
	}
	
	return ((CMProperty)p);
}
示例#3
0
static void test2() 
{
    const size32_t recsize = 17;
    printf("Test DFS\n");
    StringBuffer s;
    unsigned i;
    unsigned n;
    unsigned t;
    queryNamedGroupStore().remove("daregress_group");
    queryDistributedFileDirectory().removeEntry("daregress::superfile1");
    SocketEndpointArray epa;
    for (n=0;n<400;n++) {
        s.clear().append("192.168.").append(n/256).append('.').append(n%256);
        SocketEndpoint ep(s.str());
        epa.append(ep);
    }
    Owned<IGroup> group = createIGroup(epa); 
    queryNamedGroupStore().add("daregress_group",group,true);
    if (!queryNamedGroupStore().find(group,s.clear()))
        ERROR("Created logical group not found");
    if (stricmp(s.str(),"daregress_group")!=0)
        ERROR("Created logical group found with wrong name");
    group.setown(queryNamedGroupStore().lookup("daregress_group"));
    if (!group)
        ERROR("named group lookup failed");
    printf("Named group created    - 400 nodes\n");
    for (i=0;i<100;i++) {
        Owned<IPropertyTree> pp = createPTree("Part");
        Owned<IFileDescriptor>fdesc = createFileDescriptor();
        fdesc->setDefaultDir("c:\\thordata\\regress");
        n = 9;
        for (unsigned k=0;k<400;k++) {
            s.clear().append("192.168.").append(n/256).append('.').append(n%256);
            Owned<INode> node = createINode(s.str());
            pp->setPropInt64("@size",(n*777+i)*recsize);
            s.clear().append("daregress_test").append(i).append("._").append(n+1).append("_of_400");
            fdesc->setPart(n,node,s.str(),pp);
            n = (n+9)%400;
        }
        fdesc->queryProperties().setPropInt("@recordSize",17);
        s.clear().append("daregress::test").append(i);
        queryDistributedFileDirectory().removeEntry(s.str());
        StringBuffer cname;
        Owned<IDistributedFile> dfile = queryDistributedFileDirectory().createNew(fdesc);
        if (stricmp(dfile->getClusterName(0,cname),"daregress_group")!=0)
            ERROR1("Cluster name wrong %d",i);
        s.clear().append("daregress::test").append(i);
        dfile->attach(s.str());
    }
    printf("DFile create done      - 100 files\n");
    unsigned samples = 5;
    t = 33;
    for (i=0;i<100;i++) {
        s.clear().append("daregress::test").append(t);
        if (!queryDistributedFileDirectory().exists(s.str())) 
            ERROR1("Could not find %s",s.str());
        Owned<IDistributedFile> dfile = queryDistributedFileDirectory().lookup(s.str());
        if (!dfile) {
            ERROR1("Could not find %s",s.str());
            continue;
        }
        offset_t totsz = 0;
        n = 11;
        for (unsigned k=0;k<400;k++) {
            Owned<IDistributedFilePart> part = dfile->getPart(n);
            if (!part) {
                ERROR2("part not found %d %d",t,n);
                continue;
            }
            s.clear().append("192.168.").append(n/256).append('.').append(n%256);
            Owned<INode> node = createINode(s.str());
            if (!node->equals(part->queryNode()))
                ERROR2("part node mismatch %d, %d",t,n);
            if (part->getFileSize(false,false)!=(n*777+t)*recsize)
                ERROR4("size node mismatch %d, %d, %d, %d",t,n,(unsigned)part->getFileSize(false,false),(n*777+t)*recsize);
            s.clear().append("daregress_test").append(t).append("._").append(n+1).append("_of_400");
/* ** TBD
            if (stricmp(s.str(),part->queryPartName())!=0)
                ERROR4("part name mismatch %d, %d '%s' '%s'",t,n,s.str(),part->queryPartName());
*/
            totsz += (n*777+t)*recsize;
            if ((samples>0)&&(i+n+t==k)) {
                samples--;
                RemoteFilename rfn;
                part->getFilename(rfn,samples%2);
                StringBuffer fn;
                rfn.getRemotePath(fn);
                printf("SAMPLE: %d,%d %s\n",t,n,fn.str());
            }
            n = (n+11)%400;
        }
        if (totsz!=dfile->getFileSize(false,false))
            ERROR1("total size mismatch %d",t);
        t = (t+33)%100; 
    }
    printf("DFile lookup done      - 100 files\n");

    // check iteration
    __int64 crctot = 0;
    unsigned np = 0;
    unsigned totrows = 0;
    Owned<IDistributedFileIterator> fiter = queryDistributedFileDirectory().getIterator("daregress::*",false); 
    Owned<IDistributedFilePartIterator> piter;
    ForEach(*fiter) {
        piter.setown(fiter->query().getIterator()); 
        ForEach(*piter) {
            RemoteFilename rfn;
            StringBuffer s;
            piter->query().getFilename(rfn,0);
            rfn.getRemotePath(s);
            piter->query().getFilename(rfn,1);
            rfn.getRemotePath(s);
            crctot += crc32(s.str(),s.length(),0);
            np++;
            totrows += (unsigned)(piter->query().getFileSize(false,false)/fiter->query().queryProperties().getPropInt("@recordSize",-1));
        }
    }
    piter.clear();
    fiter.clear();
    printf("DFile iterate done     - %d parts, %d rows, CRC sum %"I64F"d\n",np,totrows,crctot);
    Owned<IDistributedSuperFile> sfile;
    sfile.setown(queryDistributedFileDirectory().createSuperFile("daregress::superfile1",true));
    for (i = 0;i<100;i++) {
        s.clear().append("daregress::test").append(i);
        sfile->addSubFile(s.str());
    }
    sfile.clear();
    sfile.setown(queryDistributedFileDirectory().lookupSuperFile("daregress::superfile1"));
    if (!sfile) {
        ERROR("Could not find added superfile");
        return;
    }
    __int64 savcrc = crctot;
    crctot = 0;
    np = 0;
    totrows = 0;
    size32_t srs = (size32_t)sfile->queryProperties().getPropInt("@recordSize",-1);
    if (srs!=17)
        ERROR1("Superfile does not match subfile row size %d",srs);
    piter.setown(sfile->getIterator()); 
    ForEach(*piter) {
        RemoteFilename rfn;
        StringBuffer s;
        piter->query().getFilename(rfn,0);
        rfn.getRemotePath(s);
        piter->query().getFilename(rfn,1);
        rfn.getRemotePath(s);
        crctot += crc32(s.str(),s.length(),0);
        np++;
        totrows += (unsigned)(piter->query().getFileSize(false,false)/srs);
    }
    piter.clear();
    printf("Superfile iterate done - %d parts, %d rows, CRC sum %"I64F"d\n",np,totrows,crctot);
    if (crctot!=savcrc)
        ERROR("SuperFile does not match sub files");
    unsigned tr = (unsigned)(sfile->getFileSize(false,false)/srs); 
    if (totrows!=tr)
        ERROR1("Superfile size does not match part sum %d",tr);
    sfile->detach();
    sfile.clear();
    sfile.setown(queryDistributedFileDirectory().lookupSuperFile("daregress::superfile1"));
    if (sfile)
        ERROR("Superfile deletion failed");
    t = 37;
    for (i=0;i<100;i++) {
        s.clear().append("daregress::test").append(t);
        if (i%1) {
            Owned<IDistributedFile> dfile = queryDistributedFileDirectory().lookup(s.str());
            if (!dfile)
                ERROR1("Could not find %s",s.str());
            dfile->detach();
        }
        else 
            queryDistributedFileDirectory().removeEntry(s.str());
        t = (t+37)%100; 
    }
    printf("DFile removal complete\n");
    t = 39;
    for (i=0;i<100;i++) {
        if (queryDistributedFileDirectory().exists(s.str()))
            ERROR1("Found %s after deletion",s.str());
        Owned<IDistributedFile> dfile = queryDistributedFileDirectory().lookup(s.str());
        if (dfile)
            ERROR1("Found %s after deletion",s.str());
        t = (t+39)%100; 
    }
    printf("DFile removal check complete\n");
    queryNamedGroupStore().remove("daregress_group");
    if (queryNamedGroupStore().lookup("daregress_group"))
        ERROR("Named group not removed");
}
示例#4
0
/* Actually open the connection and do some http parsing, handle any 302
 * responses within here.
 */
static int open_relay_connection (client_t *client, relay_server *relay, relay_server_master *master)
{
    int redirects = 0;
    http_parser_t *parser = NULL;
    connection_t *con = &client->connection;
    char *server = strdup (master->ip);
    char *mount = strdup (master->mount);
    int port = master->port, timeout = master->timeout, ask_for_metadata = relay->mp3metadata;
    char *auth_header = NULL;

    if (relay->username && relay->password)
    {
        char *esc_authorisation;
        unsigned len = strlen(relay->username) + strlen(relay->password) + 2;

        DEBUG2 ("using username %s for %s", relay->username, relay->localmount);
        auth_header = malloc (len);
        snprintf (auth_header, len, "%s:%s", relay->username, relay->password);
        esc_authorisation = util_base64_encode(auth_header);
        free(auth_header);
        len = strlen (esc_authorisation) + 24;
        auth_header = malloc (len);
        snprintf (auth_header, len,
                "Authorization: Basic %s\r\n", esc_authorisation);
        free(esc_authorisation);
    }

    while (redirects < 10)
    {
        sock_t streamsock;
        char *bind = NULL;

        /* policy decision, we assume a source bind even after redirect, possible option */
        if (master->bind)
            bind = strdup (master->bind);

        if (bind)
            INFO4 ("connecting to %s:%d for %s, bound to %s", server, port, relay->localmount, bind);
        else
            INFO3 ("connecting to %s:%d for %s", server, port, relay->localmount);

        con->con_time = time (NULL);
        relay->in_use = master;
        streamsock = sock_connect_wto_bind (server, port, bind, timeout);
        free (bind);
        if (connection_init (con, streamsock, server) < 0)
        {
            WARN2 ("Failed to connect to %s:%d", server, port);
            break;
        }

        parser = get_relay_response (con, mount, server, ask_for_metadata, auth_header);

        if (parser == NULL)
        {
            ERROR4 ("Problem trying to start relay on %s (%s:%d%s)", relay->localmount,
                    server, port, mount);
            break;
        }
        if (strcmp (httpp_getvar (parser, HTTPP_VAR_ERROR_CODE), "302") == 0)
        {
            /* better retry the connection again but with different details */
            const char *uri, *mountpoint;
            int len;

            uri = httpp_getvar (parser, "location");
            INFO1 ("redirect received %s", uri);
            if (strncmp (uri, "http://", 7) != 0)
                break;
            uri += 7;
            mountpoint = strchr (uri, '/');
            free (mount);
            if (mountpoint)
                mount = strdup (mountpoint);
            else
                mount = strdup ("/");

            len = strcspn (uri, ":/");
            port = 80;
            if (uri [len] == ':')
                port = atoi (uri+len+1);
            free (server);
            server = calloc (1, len+1);
            strncpy (server, uri, len);
            connection_close (con);
            httpp_destroy (parser);
            parser = NULL;
        }
        else
        {
            if (httpp_getvar (parser, HTTPP_VAR_ERROR_MESSAGE))
            {
                ERROR3 ("Error from relay request on %s (%s %s)", relay->localmount,
                        master->mount, httpp_getvar(parser, HTTPP_VAR_ERROR_MESSAGE));
                client->parser = NULL;
                break;
            }
            sock_set_blocking (streamsock, 0);
            thread_rwlock_wlock (&relay->source->lock);
            client->parser = parser; // old parser will be free in the format clear
            thread_rwlock_unlock (&relay->source->lock);
            client->connection.discon_time = 0;
            client->connection.con_time = time (NULL);
            client_set_queue (client, NULL);
            free (server);
            free (mount);
            free (auth_header);

            return 0;
        }
        redirects++;
    }
    /* failed, better clean up */
    free (server);
    free (mount);
    free (auth_header);
    if (parser)
        httpp_destroy (parser);
    connection_close (con);
    con->con_time = time (NULL); // sources count needs to drop in such cases
    if (relay->in_use) relay->in_use->skip = 1;
    return -1;
}
void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) {
    PortMixer *mixer = (PortMixer *)id;

    TRACE1(">>PORT_GetControls (portIndex = %d)\n", portIndex);

    if (portIndex < 0 || portIndex >= mixer->portCount) {
        ERROR1("<<PORT_GetControls: line (portIndex = %d) not found\n", portIndex);
        return;
    }

    PortLine *port = &(mixer->ports[portIndex]);

    if (mixer->deviceControlCount < 0) {    // not initialized
        OSStatus err;
        UInt32 size;
        // deviceControlCount is overestimated
        // because we don't actually filter by if the owned objects are controls
        err = GetAudioObjectPropertySize(mixer->deviceID, kAudioObjectPropertyScopeGlobal,
            kAudioObjectPropertyOwnedObjects, &size);

        if (err) {
            OS_ERROR1(err, "PORT_GetControls (portIndex = %d) get OwnedObject size", portIndex);
        } else {
            mixer->deviceControlCount = size / sizeof(AudioObjectID);
            TRACE1("  PORT_GetControls: detected %d owned objects\n", mixer->deviceControlCount);

            AudioObjectID controlIDs[mixer->deviceControlCount];

            err = GetAudioObjectProperty(mixer->deviceID, kAudioObjectPropertyScopeGlobal,
                kAudioObjectPropertyOwnedObjects, sizeof(controlIDs), controlIDs, 1);

            if (err) {
                OS_ERROR1(err, "PORT_GetControls (portIndex = %d) get OwnedObject values", portIndex);
            } else {
                mixer->deviceControls = (AudioControl *)calloc(mixer->deviceControlCount, sizeof(AudioControl));

                for (int i = 0; i < mixer->deviceControlCount; i++) {
                    AudioControl *control = &mixer->deviceControls[i];

                    control->controlID = controlIDs[i];

                    OSStatus err1 = GetAudioObjectProperty(control->controlID, kAudioObjectPropertyScopeGlobal,
                        kAudioObjectPropertyClass, sizeof(control->classID), &control->classID, 1);
                    OSStatus err2 = GetAudioObjectProperty(control->controlID, kAudioObjectPropertyScopeGlobal,
                        kAudioControlPropertyScope, sizeof(control->scope), &control->scope, 1);
                    OSStatus err3 = GetAudioObjectProperty(control->controlID, kAudioObjectPropertyScopeGlobal,
                        kAudioControlPropertyElement, sizeof(control->channel), &control->channel, 1);
                    if (err1 || err2 || err3) { // not a control or other error
                        control->classID = 0;
                        continue;
                    }

                    TRACE4("- control 0x%x, class='%s', scope='%s', channel=%d\n",
                        control->controlID, FourCC2Str(control->classID), FourCC2Str(control->scope), control->channel);
                }
            }
        }
    }

    if (mixer->deviceControlCount <= 0) {
        TRACE1("<<PORT_GetControls (portIndex = %d): no owned AudioControls\n", portIndex);
        return;
    }

    int totalChannels = GetChannelCount(mixer->deviceID, port->scope == kAudioDevicePropertyScopeOutput ? 1 : 0);

    // collect volume and mute controls
    AudioControl* volumeControls[totalChannels+1];  // 0 - for master channel
    memset(&volumeControls, 0, sizeof(AudioControl *) * (totalChannels+1));
    AudioControl* muteControls[totalChannels+1];  // 0 - for master channel
    memset(&muteControls, 0, sizeof(AudioControl *) * (totalChannels+1));

    for (int i=0; i<mixer->deviceControlCount; i++) {
        AudioControl *control = &mixer->deviceControls[i];
        if (control->classID == 0 || control->scope != port->scope || control->channel > (unsigned)totalChannels) {
            continue;
        }
        if (control->classID == kAudioVolumeControlClassID) {
            if (volumeControls[control->channel] == NULL) {
                volumeControls[control->channel] = control;
            } else {
                ERROR4("WARNING: duplicate VOLUME control 0x%x, class='%s', scope='%s', channel=%d\n",
                    control->controlID, FourCC2Str(control->classID), FourCC2Str(control->scope), control->channel);
            }
        } else if (control->classID == kAudioMuteControlClassID) {
            if (muteControls[control->channel] == NULL) {
                muteControls[control->channel] = control;
            } else {
                ERROR4("WARNING: duplicate MUTE control 0x%x, class='%s', scope='%s', channel=%d\n",
                    control->controlID, FourCC2Str(control->classID), FourCC2Str(control->scope), control->channel);
            }
        } else {
#ifdef USE_ERROR
            if (control->classID != 0) {
                ERROR4("WARNING: unhandled control 0x%x, class='%s', scope='%s', channel=%d\n",
                    control->controlID, FourCC2Str(control->classID), FourCC2Str(control->scope), control->channel);
            }
#endif
        }
    }

    ////////////////////////////////////////////////////////
    // create java control hierarchy

    void *masterVolume = NULL, *masterMute = NULL, *masterBalance = NULL;
    // volumeControls[0] and muteControls[0] - master volume/mute
    // volumeControls[n] and muteControls[n] (n=1..totalChannels) - corresponding channel controls
    if (volumeControls[0] != NULL) {    // "master volume" AudioControl
        masterVolume = CreatePortControl(mixer, creator, PortControl::Volume, volumeControls, 0, 1);
    } else {
        if (ValidControlCount(volumeControls, 1, totalChannels) == totalChannels) {
            // every channel has volume control => create virtual master volume
            masterVolume = CreatePortControl(mixer, creator, PortControl::Volume, volumeControls, 1, totalChannels);
        } else {
            TRACE2("  PORT_GetControls (master volume): totalChannels = %d, valid volume controls = %d\n",
                totalChannels, ValidControlCount(volumeControls, 1, totalChannels));
        }
    }

    if (muteControls[0] != NULL) {      // "master mute"
        masterMute = CreatePortControl(mixer, creator, PortControl::Mute, muteControls, 0, 1);
    } else {
        if (ValidControlCount(muteControls, 1, totalChannels) == totalChannels) {
            // every channel has mute control => create virtual master mute control
            masterMute = CreatePortControl(mixer, creator, PortControl::Mute, muteControls, 1, totalChannels);
        } else {
            TRACE2("  PORT_GetControls (master mute): totalChannels = %d, valid volume controls = %d\n",
                totalChannels, ValidControlCount(muteControls, 1, totalChannels));
        }
    }

    // virtual balance
    if (totalChannels == 2) {
        if (ValidControlCount(volumeControls, 1, totalChannels) == totalChannels) {
            masterBalance = CreatePortControl(mixer, creator, PortControl::Balance, volumeControls, 1, totalChannels);
        } else {
            TRACE2("  PORT_GetControls (naster balance): totalChannels = %d, valid volume controls = %d\n",
                totalChannels, ValidControlCount(volumeControls, 1, totalChannels));
        }
    }

    // add "master" controls
    if (masterVolume != NULL) {
        creator->addControl(creator, masterVolume);
    }
    if (masterBalance != NULL) {
        creator->addControl(creator, masterBalance);
    }
    if (masterMute != NULL) {
        creator->addControl(creator, masterMute);
    }

    // don't add per-channel controls for mono & stereo - they are handled by "master" controls
    // TODO: this should be reviewed to handle controls other than mute & volume
    if (totalChannels > 2) {
        // add separate compound control for each channel (containing volume and mute)
        // (ensure that we have controls)
        if (ValidControlCount(volumeControls, 1, totalChannels) > 0 || ValidControlCount(muteControls, 1, totalChannels) > 0) {
            for (int ch=1; ch<=totalChannels; ch++) {
                // get the channel name
                char *channelName;
                CFStringRef cfname = NULL;
                const AudioObjectPropertyAddress address = {kAudioObjectPropertyElementName, port->scope, ch};
                UInt32 size = sizeof(cfname);
                OSStatus err = AudioObjectGetPropertyData(mixer->deviceID, &address, 0, NULL, &size, &cfname);
                if (err == noErr) {
                    CFIndex length = CFStringGetLength(cfname) + 1;
                    channelName = (char *)malloc(length);
                    CFStringGetCString(cfname, channelName, length, kCFStringEncodingUTF8);
                    CFRelease(cfname);
                } else {
                    channelName = (char *)malloc(16);
                    sprintf(channelName, "Ch %d", ch);
                }

                void* jControls[2];
                int controlCount = 0;
                if (volumeControls[ch] != NULL) {
                    jControls[controlCount++] = CreatePortControl(mixer, creator, PortControl::Volume, volumeControls, ch, 1);
                }
                if (muteControls[ch] != NULL) {
                    jControls[controlCount++] = CreatePortControl(mixer, creator, PortControl::Mute, muteControls, ch, 1);
                }
                // TODO: add any extra controls for "other" controls for the channel

                void *compoundControl = creator->newCompoundControl(creator, channelName, jControls, controlCount);
                creator->addControl(creator, compoundControl);

                free(channelName);
            }
        }
    }

    AddChangeListeners(mixer);

    TRACE1("<<PORT_GetControls (portIndex = %d)\n", portIndex);
}
																	CM_CFUNCTIONS

/* The following generates a segment directive for Mac only due to 32K Jump Table 			*/
/* Limitations.  If you don't know what I'm talking about don't worry about it.  The		*/
/* default is not to generate the pragma.  Theoritically unknown pragmas in ANSI won't	*/
/* choke compilers that don't recognize them.  Besides why would they be looked at if		*/
/* it's being conditionally skipped over anyway?  I know, famous last words!						*/

#if CM_MPW
#pragma segment CMTypePropertyOps
#endif
																	

/*----------------------------------------------*
 | CMRegisterType - register a global type name |
 *----------------------------------------------*
 
 The specified type name is registered as a type in the specified container.  A refNum
 for it is returned.  If the type name already exists, the refNum for it is returned.
 
 Note, types may be used to create dynamic values when passed to CMNewValue().  Such types
 must have a metahandler registered for them and that metahandler must have handler 
 routines for "use value", "new value", and "metadata" operation types.  See
   DynValus.c    for a full explaination of dynamic values (more than you probably ever
 want to know).
*/

CMType CM_FIXEDARGS CMRegisterType(CMContainer targetContainer, CMconst_CMGlobalName name)
{
	TOCObjectPtr 	t;
	GlobalNamePtr g;
	ContainerPtr 	container = (ContainerPtr)targetContainer;
	
	NOPifNotInitialized(NULL);												/* NOP if not initialized!					*/
	
	/* See if the type global name already exists...																			*/
	
	g = cmLookupGlobalName(container->globalNameTable, (CM_UCHAR *)name);
	
	if (!SessionSuccess) {
		ERROR2(CM_err_GloblaNameError, name, CONTAINERNAME);
		return (NULL);
	}
	
	/* If the name previously existed, cmLookupGlobalName() will return a pointer to the	*/
	/* global name entry.  Even deleted global names have entries!  But we can tell that	*/
	/* because the value back pointer in the entry is NULLed out. If we do have a already */
	/* existing entry, just return the owning object pointer after one last validation 		*/
	/* that it is indeed a type object (so I'm paranoid).																	*/
	
	if (g && g->theValue) {														/* previously existing name					*/
		t = g->theValue->theValueHdr->theProperty->theObject;
		if ((t->objectFlags & TypeObject) == 0) {
			ERROR4(CM_err_MultTypeProp, "type", name, CONTAINERNAME,
						 (t->objectFlags & PropertyObject) ? "property" : "object");
			t = NULL;
		} else
			++t->useCount;																/* bump this object's use count			*/
	} else {																					/* a new name												*/
		t = cmDefineGlobalNameObject(container, container->nextUserObjectID, CM_StdObjID_GlobalTypeName,
																 CM_StdObjID_7BitASCII, (CM_UCHAR *)name,
																 container->generation, 0, TypeObject);
		if (t) {
			t->useCount = 1;															/* initial use of this object				*/
			IncrementObjectID(container->nextUserObjectID);
		}
	}
		
	return ((CMType)t);
}