Overview

The ROSE library provides many features as ordinary functions, rather than as member functions on classes. These functions are documented below.

rose_clear_select()

void rose_clear_select(
	RoseUnion * sel
	);

The rose_clear_select() function unsets the value and the attribute of RoseUnion to NULL, and moves any intermediate, nested RoseUnion objects to the trash design. See rose_get_nested_object() for more discussion on nested EXPRESS SELECTs.

rose_compute_backptrs()

void rose_compute_backptrs(
	RoseDesign * des
	);

The rose_compute_backptrs() function traverses a design and builds a table of all the backpointers. This must be done before any of the backpointer operations are performed, or if the instance data changes. When you are finished using them, you can release the memory by calling rose_release_backptrs.

See Backpointers for more discussion.

rose_compute_refcount()

void rose_compute_refcount(
	RoseDesign * des
	);

The rose_compute_refcount() function computes the reference counts for all instances in a design. This should be done before calling any of the reference count functions, or if the instance data changes.

See Reference Counting for more discussion.

rose_create_select()

RoseUnion * rose_create_select(
	RoseDomain * sel_type,
	RoseObject * obj
	);

The rose_create_select() function creates an instance of a RoseUnion which contains the specified object as its value. The sel_type parameter identifies the type of the RoseUnion that is created and returned. This function will, if necessary, create a nested sequence of RoseUnion objects in the same way as rose_put_nested_object().

If the object of the indicated type cannot be placed in the indicated select type, this function returns NULL.

rose_date_add_secs()

const char * rose_date_add_secs(
	RoseStringObject &retstr,
	const char * time_begin,
	double secs
	);

The rose_date_dec_secs() function adds by the given number of seconds to the time in a given ISO 8601 time and date string. To subtract seconds, just pass in a negative value for the seconds.

The resulting ISO 8601 string is stored in the RoseStringObject that is passed in and the function returns the result as a const char* for immediate use. The function returns zero if the input string could not be parsed due to errors.

#define MINUTE 60
#define HOUR 3600
#define DAY 86400

RoseStringObject work;

rose_date_add_secs(work, 2000-12-31T22:20:30-04:00,  8 * HOUR);
printf(%s\n, work.as_const());
==> Result:  2001-01-01T06:20:30-04:00

rose_date_add_secs(work, 2000-12-31T22:20:30-04:00,  -365 * DAY);
printf(%s\n, work.as_const());
==> Result:  2000-12-31T22:20:30-04:00   (2000 is a leap year)

If the date is not given, it is assumed to be 0000-01-01 and will remain omitted in the result unless it changes by a date rollover.

rose_date_add_secs(work, 00:20:30Z,  4 * HOUR);
printf(%s\n, work.as_const());
==> Result:  04:20:30Z

rose_date_add_secs(work, 00:20:30Z,  -4 * HOUR);
printf(%s\n, work.as_const());
==> Result: -0001-12-31T20:20:30Z

rose_date_cmp()

int rose_date_cmp(
	const char * time1,
	const char * time2
	);

The rose_date_cmp() function compares two ISO 8601 time and date strings. The result will be positive if the first string is later in time than the second string, and negative if the opposite is true. The function considers all time zone adjustments in the comparison. An input string is considered to be all zeros if it could not be parsed due to errors.

void cmp(int res) {
     if (!res) printf (Equal\n);
     else if (res > 0)
     	printf (DATE 1 greater\n);
     else
	printf (DATE 2 greater\n);
}

cmp(rose_date_cmp(2019-06-30T14:20:30.55Z, 2019-06-30T14:20:30Z));
==> DATE1 greater

cmp(rose_date_cmp(2019-05-05T00:20:30+04:00, 2019-05-05T23:20:30Z));
==> DATE2 greater

cmp(rose_date_cmp(2019-02-28T22:20:30-04:00, 2019-03-01T02:20:30Z));
==> Equal (different time zones but representing the same time)

diff(rose_date_diff_secs(2019-02-29, 2019-03-01));
==> DATE2 greater (bad DATE1 string, 2019 is not a leap year)

rose_date_diff_secs()

double rose_date_diff_secs(
	const char * time_end,
	const char * time_begin
	);

The rose_date_diff_secs() function finds the difference, in seconds, between two ISO 8601 time and date strings. The result will be positive if the first string is later in time than the second string, and negative if the opposite is true. The function returns ROSE_NULL_REAL if either input string could not be parsed due to errors.

void diff(double secs) {
     if (secs == ROSE_NULL_REAL)
      	printf (INPUT ERROR\n);
     else
	printf (%.3f secs\n, secs);
}

diff(rose_date_diff_secs(2019-06-30T14:20:30.55Z, 2019-06-30T14:20:30Z));
==> 0.550 secs

diff(rose_date_diff_secs(2019-05-05T00:20:30+04:00, 2019-05-05T23:20:30Z));
==> -97200.000 secs (negative 1 day, 3 hrs)

diff(rose_date_diff_secs(2019-02-28T22:20:30-04:00, 2019-03-01T02:20:30Z));
==> 0.000 secs (different time zones but representing the same time)

diff(rose_date_diff_secs(2019-02-29, 2019-03-01));
==> INPUT ERROR (2019 is not a leap year)

rose_date_format()

const char * rose_date_format(
	RoseStringObject &retstr,
	time_t tm
	);

const char * rose_date_format(
	RoseStringObject &retstr,
	int as_year,
	int as_month,
	int as_day,
	int as_hour,
	int as_minute,
	double as_sec,
	int tz_hrs,
	int tz_mins
	);

The rose_date_format() function formats different inputs to an ISO 8601 time and date string. The string is stored in the RoseStringObject that is passed in and the function returns the result as a const char* for immediate use.

ISO 8601 strings are used in a variety of contexts and can include date, time, and the time zone offset from UTC. Some examples are shown below.

2006-11-16			date only
2006-11-16T17:05:17		date and time
2006-11-16T17:05:17.1234	date and time to milliseconds
2006-11-16T17:05:17-05:00	date, time, and offset from UTC

The version that takes a time_t value creates a string given in the local time, including the time zone offset returned by rose_date_utc_offset_secs(). Use rose_date_format_utc() to format a time_t as a string given in UTC.

The version that takes individual components creates an ISO 8601 string in any time zone with varying levels of detail. If values are omitted by passing ROSE_NULL_INT (or ROSE_NULL_REAL for the seconds), the function will create a string without them, where legal. You can use this to make strings with just a date component, just a time component, just hours, just hours and minutes, or no time zone offset.

The seconds component is a double and can contain fractional seconds. The string will have up to six digits of decimal precision, separated by a full stop '.'. ISO 8601 also allows comma ',' as a decimal separator, but full stop appears to be more common usage in MTConnect streams and the like.

rose_date_format_utc()

const char * rose_date_format_utc(
	RoseStringObject &retstr,
	time_t tm
	);

The rose_date_format_utc() function formats a time_t value to an ISO 8601 time and date string in UTC. Use rose_date_format() to format a time_t as a string given in the local time zone.

The string is stored in the RoseStringObject that is passed in and the function returns the result as a const char* for immediate use.

rose_date_inc_secs()

int rose_date_inc_secs(
	int &as_year,
	int &as_month,
	int &as_day,
	int &as_hour,
	int &as_minute,
	double &as_sec,
	double incsecs
	);

The rose_date_inc_secs() function increments the discrete components of a time value by a given number of seconds. This is similar to rose_date_add_secs() but modifies parsed values passed by reference. To subtract seconds, just pass in a negative value for the increment. The function returns zero on sucess or nonzero if the input contains range errors.

rose_date_now / now_ms()

const char * rose_date_now(
	RoseStringObject &retstr
	);

const char * rose_date_now_ms(
	RoseStringObject &retstr
	);

The rose_date_now() and rose_date_now_ms() functions create an ISO 8601 string for the current local time. The string created by the "now" version is accurate to the second while the "now_ms" version includes fractional seconds. The resolution varies from platform to platform but is at least to millisecond resolution. See rose_date_format() for more information on the ISO 8601 format. The rose_date_utc_now() function returns a UTC time string rather than the local time.

rose_date_parse()

int rose_date_parse(
	const char * datestr,
	int &as_year,
	int &as_month,
	int &as_day,
	int &as_hour,
	int &as_minute,
	double &as_sec,
	int &tz_hrs,
	int &tz_mins
	);

The rose_date_parse() function parses an ISO 8601 time string into individual values. It recognizes most alternatives and omitted values allowed by ISO 8601, such as the extended and basic representations, ordinal dates, week dates, and fractional hours. These alternative representations will be converted into conventional calendar dates and hour/minute/second values.

When a value is omitted, the the parameter will be set to ROSE_NULL_INT, or ROSE_NULL_REAL for the seconds. This function is the inverse of rose_date_format(). The function returns zero on success or non-zero if the string could not be parsed due to errors.

Some examples of ISO 8601 strings and the parsed values:

2019-06-30T14:20:30Z
  ==> Y: 2019 M: 06 D: 30      H: 14 M: 20 S: 30      TZhr: 0 TZmin: 0

2019-06-30T14:20:30.65Z
  ==> Y: 2019 M: 06 D: 30      H: 14 M: 20 S: 30.65   TZhr: 0 TZmin: 0

2020-08-06T15:21:03-04:00
  ==> Y: 2020 M: 08 D: 06      H: 15 M: 21 S: 03      TZhr: -4 TZmin: 0

2019-06-30T14
  ==> Y: 2019 M: 06 D: 30      H: 14 (all others null)

1972-06
  ==> Y: 1972 M: 06  (all others null)

14:20:30Z
  ==> (date values null)       H: 14 M: 20 S: 30      TZhr: 0 TZmin: 0

Some of the less common ISO 8601 string representations. Note that these are converted into conventional values:

2020-060T14Z     (ordinal date -- day of year)
  ==> Y: 2020 M: 02 D: 29      H: 14 (min/sec null)   TZhr: 0 TZmin: 0

1971-W52-06T14Z  (week of year and day date)
  ==> Y: 1972 M: 01 D: 01      H: 14 (min/sec null)   TZhr: 0 TZmin: 0

1971-07-25T14.5  (fractional hour)
  ==> Y: 1972 M: 07 D: 25      H: 14 M: 30 S: 00      (time zone null)

1971-07-25T14:25.5  (fractional minute)
  ==> Y: 1972 M: 07 D: 25      H: 14 M: 25 S: 30      (time zone null)

rose_date_utc_now / now_ms()

const char * rose_date_utc_now(
	RoseStringObject &retstr
	);

const char * rose_date_utc_now_ms(
	RoseStringObject &retstr
	);

The rose_date_utc_now() and rose_date_utc_now_ms() functions create an ISO 8601 string for the current local time. The string created by the "now" version is accurate to the second while the "now_ms" version includes fractional seconds. The resolution varies from platform to platform but is at least to millisecond resolution. See rose_date_utc_format() for more information on the ISO 8601 format. The rose_date_now() function returns a time string in the local time zone rather than UTC.

rose_date_utc_offset_secs()

long rose_date_utc_offset_secs();

The rose_date_utc_offset_secs() function returns the UTC offset, measured in seconds, that is used by the computer for calculating local time. The value is signed and is positive for time zones to the east of UTC and negative for zones to the west.

rose_dir_exists()

int rose_dir_exists(
	const char * utf8_path
	);

The rose_dir_exists() function tests whether a directory with a given name exists on secondary storage. The "fname" string should be a UTF-8 directory path. On UNIX machines, this will call the POSIX stat() function. On Windows, the function will convert the UTF-8 path to wide characters and call _wstat().

rose_domain_name_cmp()

int rose_domain_name_cmp(
	const void * a, 
	const void * b
	);

The rose_domain_name_cmp() function is a variation of strcmp() that compares two EXPRESS type names using the Part 21 collating sequence. This compares as if the names were uppercase, which results in the correct collating sequence when underscores appear in the names. Is used internally with qsort() to order an array of RoseDomain pointers into the sequence used by the list of types in the STEP Part 21 external mapping.

rose_empty_trash()

void rose_empty_trash();

The rose_empty_trash() function traverses every persistent object in memory, nulling out pointers to non-persistent objects or objects in the trashcan design. Then it will reclaim memory by deleting the contents of the rose_trash() trashcan design. Persistent objects can be moved it to the trashcan with the rose_move_to_trash() function.

See Deleting Objects for more discussion.

RoseDesign * d;
Point * p_pnt = pnewIn(d) Point;

rose_move_to_trash (p_pnt);    /* moves from design to trash */
rose_empty_trash();            /* clears bad pointers, deletes obj */

rose_enum_to_string()

const char * rose_enum_to_string (
    RoseEnum val,
    RoseAttribute * att
    );

const char * rose_enum_to_string (
    RoseEnum val,
    RoseTypePtr& slottype
    );

The rose_enum_to_string() function returns searches the C++ type information for the string enumerator matching a numeric value. This function returns a null string if value is ROSE_NULL_ENUM or out of range. Use rose_string_to_enum() to convert values in the other direction.

rose_expand_substitutes()

RoseObject * rose_expand_substitutes(
	RoseObject * obj
	);

The rose_expand_substitutes() function takes a pointer to an object and either returns the same pointer, or a pointer to a substitute object if one has been registered using either the rose_register_substitute() or rose_mutate() functions.

RoseObject * obj;

obj = rose_expand_substitutes (obj);
/* now we are sure to have the most up-to-date pointer if 
 * there was some substitution or mutation going on
 */

rose_file_exists()

int rose_file_exists(
	const char * fname
	);

The rose_file_exists() function returns a boolean value indicating if a file with the given name exists on secondary storage. The "fname" string should be a UTF-8 file path. On UNIX machines, this will call the POSIX access() function. On Windows, the function will convert the UTF-8 filename to wide characters and call _waccess().

rose_file_readable()

int rose_file_readable(
	const char * fname
	);

The rose_file_readable() function tests the permissions of a given file, and returns a boolean value indicating whether the file can be read.

rose_file_remove()

void rose_file_remove(
	const char * fname
	);

The rose_file_remove() function removes a file from secondary storage. The "fname" string should be a UTF-8 file path. On UNIX machines, this will call the POSIX remove() function or unlink() as needed. On Windows, the function will convert the UTF-8 filename to wide characters and call _wremove().

rose_file_rename()

void rose_file_rename(
	const char * orig_fname,
	const char * new_fname
	);

The rose_file_rename() function renames a file on secondary storage. The old and new "fname" strings should be UTF-8 file paths. On UNIX machines, this will call the POSIX rename() function or link() as needed. On Windows, the function will convert the UTF-8 filename to wide characters and call _wrename().

rose_file_writable()

int rose_file_writable(
	const char * fname
	);

The rose_file_writable() function tests the permissions of a given file, and returns a boolean value indicating whether the file can be overwritten.

rose_get_backptrs()

RoseBackptrs * rose_get_backptrs(
	RoseObject * obj
	);

The rose_get_backptrs() function returns a handle to the computed backpointers for a given object. Call the rose_compute_backptrs() first to establish the lists of backpointers. If rose_get_backptrs() is called without previously computing the backpointers, the function will return an empty RoseBackptrs object.

See Backpointers for more discussion.

rose_get_nested_object()

RoseObject * rose_get_nested_object(
	RoseUnion * sel,
	RoseDomain * filter = NULL
	);

The rose_get_nested_object() function returns the entity or aggregate pointer held by a select instance. This function is a useful shortcut eliminates many if-then tests

This function recursively examines a RoseUnion instance until it finds a value that is not a nested RoseUnion. If the optional filter parameter is given, the return value is limited to the specified object type or a subtype.

The function returns null if the RoseUnion pointer is null or the select does not contain appropriate data, such as a string, number, or an object that does not match the filter type.

Use rose_put_nested_object() to set the value of a select.

The pattern below is common in STEP application protocols. A nested select models the types of objects that something can refer to. The get function makes it simple to look for a specific kind of value.

// The definition of a property is a characterized_definition 
// select, which could contain:
//   characterized_object,
//   characterized_product_definition (nested select)
//       product_definition,
//       product_definition_relationship
//   product_definition_shape
//   shape_aspect, 
//   shape_aspect_relationship

property_definition * prop

// We only care about values that are product_definitions
RoseObject * def = rose_get_nested_object (
     prop->definition(),
     ROSE_DOMAIN(product_definition)
     );

product_definition * pd = ROSE_CAST (product_definition, def);

rose_get/put_schema_property()

char * rose_get_schema_property(
	RoseDesign * d,
	const char * keyword
	);

void rose_put_schema_property (
	RoseDesign * d, 
	const char * keyword, 
	const char * value
	);

The get/put schema property functions are used to manage string properties stored by the compiled ROSE data-dictionary files. Application code is unlikely to use the put function since data dictionary files are part of ST-Runtime. The get function may be useful for getting Part 28 namespace information from a schema.

rose_getenv / setenv_search_path()

const char * rose_getenv_search_path();

void rose_setenv_search_path(
	const char * dir
	);

The rose_getenv_search_path() function returns the initial value of the database search path. The database search path is a list of directories used by the RoseInterface::findDesign() operation. The directories in the path are separated by the character appropriate for the platform (colons on UNIX, semicolons on Windows, and commas on VMS). See Database Search Paths for a more information on the use of the search path.

The rose_setenv_search_path() function specifies the initial value of the database search path. When the library is initialized, this path is concatenated with the system schema path and copied into the RoseInterface object. These paths are used to find data files and compiled schema files during initialization.

After the library is initialized, the RoseInterface::usePath() function can be used to change the path. The setenv function is only used to specify the initial search path. The library is initialized by the creation of the first persistent object or the first call to the RoseInterface object.

If setenv function is not used, the path will be taken from the environment or registry. The getenv function will look for a path in the $ROSE_DB environment variable or ROSE_DB registry value.

On Windows, the registry will be searched before environment variables. The location in the registry for all ROSE library settings is controlled by rose_getenv/setenv registry_key().

If a value is not found in the environment or Windows registry, a default path consisting of the current directory and a ./schemas subdirectory is used. If the function is called with a null pointer, the default value will be used. To force an empty path, set the value to a zero-length string.

If an application wanted to take the search path from a variable called $NEW_PATH, it could do so by putting the following code at the beginning of main(), before any database operations are performed:

main () {
    [ ... application init code ... ]
    rose_setenv_search_path (getenv (NEW_PATH));

    [ ... start reading files, creating objects, etc ... ]
}

In the previous example, the application would still look for the system_db directory under the ST-Developer installation to find system support files, such as the schema for Part 21 header section instances. We can make the library look elsewhere for these support files.

main () {
    [ ... application init code ... ]
    rose_setenv_search_path (getenv (NEW_PATH));
    rose_setenv_system_schema_path (/usr/local/myapp/schemas);

    [ ... start reading files, creating objects, etc ... ]
}

If these support files will always be in the normal database path, we could also disable the search for this extra directory.

main () {
    [ ... application init code ... ]
    rose_setenv_search_path (getenv (NEW_PATH));
    rose_setenv_system_schema_path ();   /* disabled */

    [ ... start reading files, creating objects, etc ... ]
}

See Also

Packaging Applications for Distribution; Database Search Paths; rose_getenv/setenv system_schema_path()

rose_getenv / setenv_system_schema_path()

const char * rose_getenv_system_schema_path();

void rose_setenv_system_schema_path(
	const char * dir
	);

The rose_getenv_system_schema_path() function returns the system schema path. This is an extra search path that is appended to the normal database search path at library initialization to make sure that the system support files are always found.

The rose_setenv_system_schema_path() function specifies the system schema path. The path can contain many directories separated by the character appropriate for the platform (colons on UNIX, semicolons on Windows, and commas on VMS). If the function is called with a null pointer, the default value will be used. To force an empty path, set the value to a zero-length string.

This path should refer to directories containing compiled schemas and auxillary files required by the ST-Developer applications. These files are normally found in the system_db/schemas directory under the ST-Developer installation.

If the setenv function is not used, the path will be taken from the environment or registry. On Windows, the registry will be searched before environment variables. The location in the registry for all ROSE library settings is controlled by rose_getenv/setenv registry_key().

First the getenv function will look for a path in the $ROSE_SYSTEM_DB environment variable or ROSE_SYSTEM_DB registry value. If a value is not found, the path will default to the system_db/schemas directory in the ST-Developer installation. The installation directory is found by looking for the $ROSE environment variable or ROSE registry value.

See Also

Packaging Applications for Distribution; Database Search Paths; rose_getenv/setenv search_path()

rose_hash_insensitive()

unsigned rose_hash_insensitive(
	const char * str
	);

The rose_hash_insensitive() function is used internally by the ROSE library. It generates a 32bit hash value from a string which treats the 7bit characters A-Z and a-z as the same values. The function ignores the locale setting and uses all other character values verbatim. This function must be given a valid pointer.

rose_io_use_write_and_rename()

int  rose_io_use_write_and_rename();
void rose_io_use_write_and_rename(int);

The rose_io_use_write_and_rename() function is a preference setting used when writing files. When true (the default) data files are written to a temp file first (with the extension .%%%) and then renamed to the final filename. When false, just write directly to the final filename.

The rename operation prevents a failed write from destroying an existing file, but some situations may require writing directly to the final filename.

rose_is_marked()

int rose_is_marked(
	RoseObject * obj, 
	RoseMark m = ROSE_MARK_CURRENT
	);

The rose_is_marked() function tests whether an object has been given a mark by rose_mark_set(). Use rose_mark_clear() to remove a mark from an object.

The function takes an optional mark handle previously returned by rose_mark_begin(). If one is not given, the function uses rose_mark_current(). The function returns zero if no handle is active.

See Mark Objects as Visited for more discussion

rose_is_system_schema()

int rose_is_system_schema(
	RoseDesign * d
	);

The rose_is_system_schema() function returns true if a RoseDesign object is a schemas that are used internally by the ROSE library. This allows an application to distinguish between system schemas that used by the ROSE library and schemas that represent an application protocol or other public schema. This is useful when deciding which schemas to write in the header of a STEP file.

rose_iso_timestamp()

const char * rose_iso_timestamp();

The rose_iso_timestamp() function returns the current time as a character string in the ISO 8601 format required by the Part 21 header file_name.time_stamp field. For example, the string 1995-05-18T14:18:59-04:00 indicates May 18, 1995 at 2:18pm, 4 hours behind UTC.

This function returns a pointer to a static buffer which will be overwritten by subsequent calls to the function. This is obsolete and rose_date_now(), which fills in a RoseStringObject should be used instead.

rose_logwin_init()

#include <rose_logwin.h>

int rose_logwin_init();

The rose_logwin_init() function registers the ST-Developer Message Window with the ROSE library so that all Part 21 syntax errors, warnings, or other status messages will be sent to a separate message window. This package is only available on Windows.

Include rose_logwin.h, call this function near the start of your application, and link against the rose_logwin.lib library. The roselog DLL must be in your path for the log window to appear. If the DLL is found, rose_logwin_init() will return non-zero. If it is not found, the function will return zero and the default error handling used.

Calling rose_logwin_wait() at the end of your program will block until the user dismisses the message box. This gives the user a chance to view the messages, particularly in short-lived programs.

The following example shows how to initialize the message window

#include <rose.h>
#include <rose_logwin.h>

int main (int argc, char ** argv) 
{
    rose_logwin_init();
    /* your code */
    rose_logwin_wait();
}

rose_logwin_wait()

void rose_logwin_wait();

The rose_logwin_wait() function does not return until the ST-Developer Message Window has been dismissed. Calling this function at the end of your program gives the user a chance to view the messages, particularly in short-lived programs.

rose_mark_begin()

typedef unsigned RoseMark;
#define ROSE_MARK_CURRENT ((RoseMark) 0)

RoseMark rose_mark_begin();

The rose_mark_begin() function initializes an object marker for use in traversals. The function returns a handle identifying a marker. You can use this handle to alternate between several marks, but most usage will be strictly nested, so you can omit the handle in the function calls and the most recent one will be used. The macro ROSE_MARK_CURRENT also refers to most recently opened mark.

When a new marker is started, no data objects will be marked. Call rose_mark_set() to add a mark, rose_is_marked() to test for a mark, and rose_mark_clear() to remove a previously placed mark.

Call rose_mark_end when the marking algorithm is finished to release the mark. To help detect code that fails to release marks, the library will warn when more than a certain number of marks are concurrently opened. You can control when warnings occur using the rose_mark_warning_at function.

Earlier versions of the ROSE library provided one non-nested mark managed with the RoseInterface beginTraversal()/endTraversal(), RoseObject visit() and wasVisited() functions. These are still present, but alias the more general rose_mark_xxx functions.

The following example shows a simple traversal which takes a list that may contain duplicates. The code marks each object as it works to make sure that no object is processed twice. See Mark Objects as Visited for more discussion

ListOfRoseObject * objs;

rose_mark_begin();
for (unsigned i=0; i<objs->size(); i++)
{
    RoseObject * obj = objs->get(i);
    if (!rose_is_marked(obj))
    {
	rose_mark_set(obj);
	/* do other things */
    }
}
rose_mark_end();

The following example shows a traversal that uses multiple marks to categorize some objects.

unsigned i;
ListOfRoseObject * objs;

RoseMark red = rose_mark_begin();
RoseMark green = rose_mark_begin();
RoseMark blue = rose_mark_begin();

// Apply several different marks based on various conditions

for (i=0; i<objs->size(); i++)
{
    RoseObject * obj = objs->get(i);
    if (/* obj is red */)    rose_mark_set(obj, red);
    if (/* obj is green */)  rose_mark_set(obj, green);
    if (/* obj is blue */)   rose_mark_set(obj, blue);
}

// Do something based on what marks an object has
for (i=0; i<objs->size(); i++)
{
    RoseObject * obj = objs->get(i);
    if (rose_is_marked(obj, red) &&
        rose_is_marked(obj, green) &&
        rose_is_marked(obj, blue))
    {
	// object is marked by all three
    }
}

rose_mark_end(red);
rose_mark_end(green);
rose_mark_end(blue);

rose_mark_clear()

void rose_mark_clear(
	RoseObject * obj, 
	RoseMark m = ROSE_MARK_CURRENT
	);

The rose_mark_clear() function removes a mark from an object. The function takes an optional mark handle previously returned by rose_mark_begin(). If not given, the function uses rose_mark_current().

To bulk unmark all objects, just end the previous mark with rose_mark_end() and begin a new one with rose_mark_begin(). Closing the old mark and opening a new one is a constant time operation.

See Mark Objects as Visited for more discussion

rose_mark_clear_all()

void rose_mark_clear_all(	
	RoseDesign * design, 
	RoseMark m = ROSE_MARK_CURRENT
	);

void rose_mark_clear_all(
	RoseMark m = ROSE_MARK_CURRENT
	);

These "clear all" functions are used for internal cleanup and examine every object in a design or in memory.

If you just want to make sure all objects are not marked, just end the previous mark with rose_mark_end() and begin a new one with rose_mark_begin(). Closing the old mark and opening a new one is a constant time operation.

rose_mark_current()

RoseMark rose_mark_current();

The rose_mark_current() function returns the handle of the mark returned by the most recent rose_mark_begin(). The library maintains a stack of marks, so nested traversals work as expected. When a mark is released by rose_mark_end(), the current mark reverts to the next most recently begun one. The function returns zero if no traversal mark is active.

See Mark Objects as Visited for more discussion

rose_mark_end()

void rose_mark_end(
	RoseMark m = ROSE_MARK_CURRENT
	);

The rose_mark_end() function releases a mark handle when a traversal algorithm is finished. The function takes an optional mark handle previously returned by rose_mark_begin(). If not given, the function uses rose_mark_current().

Releasing the rose_mark_current() handle will set the current to the next most recent active handle.

See Mark Objects as Visited for more discussion

rose_mark_set()

void rose_mark_set(
	RoseObject * obj, 
	RoseMark m = ROSE_MARK_CURRENT
	);

The rose_mark_set() function adds a mark to an object. The function takes an optional mark handle previously returned by rose_mark_begin(). If not given, the function uses rose_mark_current().

See Mark Objects as Visited for more discussion

rose_mark_warning_at()

void rose_mark_warning_at(
	unsigned max_concurrent
	);

The rose_mark_warning_at() function sets the point at which the library will warn about nested calls to rose_mark_begin(), which is done to help detect code that fails to release marks. By default, the library will warn when marks are nested more then ten deep.

rose_mkdir()

int rose_mkdir(
	const char * utf8_path
	);

The rose_mkdir() function creates a directory with a given name on secondary storage. The "fname" string should be a UTF-8 directory path. On UNIX machines, this will call the POSIX mkdir() function. On Windows, the function will convert the UTF-8 path to wide characters and call _mkdir().

rose_move_to_design()

void rose_move_to_design(
	RoseObject * obj, 
	RoseDesign * design
	);

The rose_move_to_design() function moves an object to another RoseDesign. The object is moved to the default section in the new design. This function is called by RoseObject::move() to move individual objects, but does not perform a recursive move.

The function also has an unused third argument, a RoseDomain pointer that defaults to zero. This third argument is for internal use only.

Point * pt;
RoseObject * design_1;
RoseObject * design_2;

pt = pnewIn (design_1) Point;         /* create in design 1 */
rose_move_to_design (pt, design_2);   /* move to design 2 */

pt = new Point;                       /* create non persistent obj */
rose_move_to_design (pt, design_2);   /* move into a design */

See Also

Moving and Copying Objects; rose_move_to_section(); RoseObject::move()

rose_move_to_section()

void rose_move_to_section(
	RoseObject * obj, 
	RoseDesignSection * section,
	);

The rose_move_to_section() function moves an object to a RoseDesignSection in another design. The function actually has a third argument, a RoseDomain pointer that defaults to zero. This third argument is for internal use only.

Point * pt;
RoseObject * design_1;
RoseObject * design_2;

pt = pnewIn (design_1) Point;       /* create in design 1 */

/* both to move to the default section in design 2 */
rose_move_to_design (pt, design_2);
rose_move_to_section (pt, design_2->dflt_section());

See Also

Moving and Copying Objects; Design Sections;

rose_move_to_trash()

void rose_move_to_trash(
	RoseObject * obj
	);

void rose_move_to_trash(
	RoseDesign * design
	);

The rose_move_to_trash() function moves a persistent object to the trashcan design. The trashcan design contains objects scheduled for deletion. When the trash is emptied, all persistent objects in memory are examined and any pointers to objects in the trash are reset to null. Once all pointers have been corrected, the objects are deleted.

When called on a RoseDesign, this function schedules the entire design for deletion. When emptying the trash, any pointers to objects in the trashed design will be set to null. The RoseDesign::isTrashed() function can be used to determine whether a design has been scheduled for deletion.

RoseDesign * d1, d2;

Point * pt = pnewIn(d1) Point;

rose_move_to_trash (pt);  /* mark object for deletion */
rose_move_to_trash (d2);  /* mark entire design for deletion */
rose_empty_trash();

See Also

Creating and Deleting Design Objects; Deleting Objects; rose_empty_trash(); rose_trash()

rose_mutate()

RoseObject * rose_mutate(
	RoseObject * orig, 
	RoseDomain * new_domain
	);

The rose_mutate() function creates a new object with the same attribute values of the old. Attributes are matched by name. The original object is moved to the trash and a substitution is registered from the old to the new object. The entity_id() and entity_comment(), oid(), and wasVisited() state of the object are preserved, but any user-defined RoseManagers that an application may have added are not.

References to the old object will only be updated when the trash is emptied or rose_update_object_references() is called on the design. An application can convert a particular pointer with the rose_expand_substitutes() functions.

/* creates copy of orig, moves to trash */
rose_mutate (orig, new_dom);

/* these updates references to orig */
RoseObject * oldref;
RoseObject * newref;

newref = rose_expand_substitutes(oldref);  /* one pointer */
rose_update_object_references (design);    /* one design */
rose_empty_trash();                        /* all designs */

See Also

rose_register_substitute(); rose_expand_substitutes(); rose_update_object_references(); RoseObject::copy()

rose_p21_dflt_add_schema()

RoseStatus rose_p21_dflt_add_schema(
	RoseDesign * design, 
	const char * name
	);

The rose_p21_dflt_add_schema() function is a predefined hook function used with RoseP21Parser::add_schema_fn to process each schema name in the header of a Part 21 file. This function reads the compiled data dictionary file for a schema using rose_p21_find_schema() and adds it to the design using addSchema().

Use this function to handle schemas by putting the following somewhere in your main, before you start reading files.

// This function is the default if no hook specified
RoseP21Parser::set_schemas_fn = 0;  
RoseP21Parser::add_schema_fn = 0;  

See Also

Customized Schema Handling; rose_p21_find_schema(); RoseDesign::addSchema()

rose_p21_dflt_read_comment()

void rose_p21_dflt_read_comment(
	RoseP21Lex * lex
	);

The rose_p21_dflt_read_comment() function an alias for rose_p21_read_and_discard_comment().

rose_p21_dflt_renumber()

RoseStatus rose_p21_dflt_renumber(
	RoseDesign * design
	);

The rose_p21_dflt_renumber() function is a predefined hook function used with RoseP21Writer::renumber_fnto renumber the entity instances in a Part 21 file before it is written.

This function provides all of the default renumbering behavior controlled by the RoseP21Writer::preserve_eids, RoseP21Writer::sort_eids, and RoseP21Writer::renumber_density variables. If you replace this with your own hook function, these variables will no longer have any effect.

Use this function to renumber by putting the following somewhere in your main, before you start reading files.

RoseP21Writer::renumber_fn = rose_p21_dflt_renumber;

// This function is also the default if no hook specified
RoseP21Writer::renumber_fn = 0;  

See Also

Entity ID Numbering; RoseObject::entity_id()

rose_p21_dflt_schema_name()

const char * rose_p21_dflt_schema_name(
	RoseDesign * design,
	RoseDesign * schema 
	);

The rose_p21_dflt_schema_name() function is a predefined hook function used with RoseP21Writer::schema_name_fn to provide the schema name that should appear in the header of a Part 21 file.

The function is passed two arguments, a pointer to the design being written, and a pointer to the schema (which is also a design). This function reads the name of the schema design.

Use this function to handle schemas by putting the following somewhere in your main, before you start reading files.

RoseP21Writer::schema_name_fn = rose_p21_dflt_schema_name;

// This function is also the default if no hook specified
RoseP21Writer::schema_name_fn = 0;  

See Also

Customized Schema Handling; RoseDesign::name()

rose_p21_find_schema()

RoseDesign * rose_p21_find_schema(
	const char * schema_name
	);

The rose_p21_find_schema() function searches for a rose compiled schema given a schema identifier from the header of a Part 21 file. The schema name in the header is usually uppercase and may have additional ASN/1 identifiers (the numbers in braces {1 10303 203 1 2 3}), so the function may have to do some processing name remapping before calling ROSE.findDesign() to read the design.

This function is primarily used within functions, such as rose_p21_add_schema(), that are provided to the RoseP21Parser::add_schema_fn hook.

See Also

Customized Schema Handling; rose_p21_dflt_add_schema(); RoseInterface::findDesign()

rose_p21_read_and_discard_comment()

void rose_p21_read_and_discard_comment(
	RoseP21Lex * lex
	);

The rose_p21_read_and_discard_comment() function is a predefined hook functions that can be assigned to RoseP21Lex::comment_fn to scan comments in a Part 21 file.

As described in Reading and Writing Comments a hook function is called when the Part 21 lexer encounters a comment. This function processes the comment and discards the contents.

Use this function to handle comments by putting the following somewhere in your main, before you start reading files.

RoseP21Lex::comment_fn = rose_p21_read_and_discard_comment;

// This function is also the default if no hook specified
RoseP21Lex::comment_fn = 0;  

See Also

Reading and Writing Comments; rose_p21_read_and_preserve_comment();

rose_p21_read_and_preserve_comment()

void rose_p21_read_and_preserve_comment(
	RoseP21Lex * lex
	);

The rose_p21_read_and_preserve_comment() function is a predefined hook functions that can be assigned to RoseP21Lex::comment_fn to scan comments in a Part 21 file.

As described in Reading and Writing Comments a hook function is called when the Part 21 lexer encounters a comment. This function captures the comment and associates it with the nearest object so that it is available via the RoseObject::entity_comment() function.

Use this function to handle comments by putting the following somewhere in your main, before you start reading files.

RoseP21Lex::comment_fn = rose_p21_read_and_preserve_comment;

See Also

Reading and Writing Comments; rose_p21_read_and_discard_comment(); RoseObject::entity_comment().

rose_p21_schema_name_cmp()

int rose_p21_schema_name_cmp(
	const char * name_a,
	const char * name_b
	);

The rose_p21_schema_name_cmp() function compares two schema name strings and returns a less than zero/zero/greater than zero value as with strcmp(). Schema names are usually uppercase when they appear in a Part 21 file, but this function compares them in a case-insensitive manner.

The function also ignores any leading whitespace and any trailing ASN1 identifiers "{ 1 2 3 ... }" when comparing. The function will also treat a null pointer as an empty string ("") for comparison purposes. Since ASN1 ids are ignored, a string that only contains an ASN1 identifier will also compare equal to an empty string.

const char * nm1 = FOOBAR_SCHEMA;
const char * nm2 = FOOBAR_SCHEMA { 1 10303 299 1 0 1 };
const char * nm3 =   foobar_schema;
const char * nm4 = FOOBAR_SCHEMA_NAME;

// nm1 and nm2 will be equal
if (!rose_p21_schema_name_cmp(nm1, nm2))
    printf (schema names equal!\n);

// nm1 and nm3 will be equal
if (!rose_p21_schema_name_cmp(nm1, nm3))
    printf (schema names also equal!\n);

// nm1 and nm4 will NOT be equal
if (rose_p21_schema_name_cmp(nm1, nm4))
    printf (schema names are NOT equal!\n);

// ASN1 idents are ignored so these will be equal
if (rose_p21_schema_name_cmp(, { 1 2 3 4 }))
    printf (no schema name in either, so equal!\n);

rose_p28_init()

#include <rose_p28.h>

void rose_p28_init();

The rose_p28_init() function registers the XML file handler so that applications can read and write STEP Part 28 Edition 2 XML exchange files (ISO 10303-28:2007). You must include the rose_p28.h file and link against the rosexml and rosemath libraries.

Once rose_p28_init() is called, your application will recognize STEP Part 28 XML files when reading. By default, new files are written as Part 21 but you can switch to Part 28 XML by calling RoseDesign::format() with p28 or p28-raw" strings.

See Also

STEP Part 28 XML Files; RoseDesign::format()

rose_path_all_with_ext()

void rose_path_all_with_ext (
	ListOfString &result,
	const char * dir,
	const char * ext = 0
	);

The rose_path_all_with_ext() function appends the full paths for all files in a directory that match a given extension.

When the extension parameter is omitted or a null pointer, the function searches for files with all known extensions (.stp, .step, etc). When the extension is an empty string (""), the function only looks for files that have no extension.

rose_path_base()

const char * rose_path_base (
	RoseStringObject &result,
	const char * utf8_path
	);

The rose_path_base() function extracts the file name from a path, without any leading directory or trailing extension. The name is stored in the caller-provided string object and a pointer to the resulting character buffer is returned.

This function replaced the earlier rose_basename() function, which was not thread-safe because it used a static character buffer.

RoseStringObject buf;

// buf will contain bar
rose_path_base(buf, foo/bar.baz);

printf(ext: %s\n, buf.as_const());

rose_path_cmp()

int rose_path_cmp (
	const char * a, 
	const char * b
	)

The rose_path_cmp() function compares file paths. The return value follows the same convention as strcmp(), so zero means the values are equal.

This function ignores case and treats slashes and backslashes as the same on Windows and anywhere else that is needed. The function also treats strings like "./foo.bar" and "foo.bar" as equal.

rose_path_cmp_extstr()

int rose_path_cmp_extstr (
    const char * ext1,
    const char * ext2
    );

The rose_path_cmp_extstr() function compares two strings, which are expected to both be file extensions. The return value follows the same convention as strcmp(), so zero means the values are equal.

This function ignores case and treats slashes and backslashes as the same on Windows and anywhere else that is needed. It also does not care whether the strings have a leading dot separator or not. Use rose_path_has_ext() test whether a path has a particular extension.

rose_path_dir()


const char * rose_path_dir (
	RoseStringObject &result,
	const char * utf8_path
	);

The rose_path_dir() function extracts the directory from a path, without the filename or extension. The directory is stored in the caller-provided string object and a pointer to the resulting character buffer is returned. If the path does not have a directory component, the function returns null. On Windows, the function recognizes forward and backslahes, as well as disk specifiers.

This function replaced the earlier rose_dirname() function, which was not thread-safe because it used a static character buffer.

RoseStringObject buf;

// buf will contain foo/
rose_path_dir(buf, foo/bar.baz);

printf(dir: %s\n, buf.as_const());

rose_path_ext()

const char * rose_path_ext (
	RoseStringObject &result,
	const char * utf8_path
	);

The rose_path_ext() function extracts the trailing filename extension from a path, without the filename or directory. The extension is stored in the caller-provided string object and a pointer to the resulting character buffer is returned. The string will include the dot (".") separator, so index in by one character if you just want the text. If the path does not have a file extension, the function returns null.

This function replaced the earlier rose_extname() function, which was not thread-safe because it used a static character buffer.

RoseStringObject buf;

// buf will contain .baz
rose_path_ext(buf, foo/bar.baz);

printf(ext: %s\n, buf.as_const());

rose_path_filename()

const char * rose_path_filename (
	RoseStringObject &result,
	const char * utf8_path
	);

The rose_path_filename() function extracts the full file name with extension from a path string, without any leading directory. The name is stored in the caller-provided string object and a pointer to the resulting character buffer is returned.

Call rose_path_dir() to extract the directory portion of the path, rose_path_base() for the filename without an extension, and rose_path_ext for just the extension. Use rose_path_join to assemble everything again.

RoseStringObject dir, fn, base, ext;

rose_path_dir      (dir,  foo/bar.baz);
rose_path_filename (fn,   foo/bar.baz);
rose_path_base     (base, foo/bar.baz);
rose_path_ext      (ext,  foo/bar.baz);

// After calling the functions above:
// dir is foo/
// fn  is bar.baz
// base is bar
// ext is .baz


// join the dir with filename or parts to recreate original

RoseStringObject path;
rose_path_join(path, dir, fn); 		
printf(path: %s\n, path.as_const());  // foo/bar.baz


rose_path_join(path, dir, base, ext);
printf(path: %s\n, path.as_const());  // also foo/bar.baz

rose_path_has_ext()

int rose_path_has_ext (
	const char * path,
	const char * ext
	);

The rose_path_has_ext() function returns true if a file path matches a given extension. The extension may be specified with or without the dot separator. If the extension string is null or empty, the function returns true only if the file path has no extension.

rose_path_has_known_ext()

int rose_path_has_known_ext (
	const char * path
	);

The rose_path_has_known_ext() function returns true if a file path has an extension that matches any of the ones known by the library, such as "stp", "step", "p21", or "ifc".

rose_path_join()

const char * rose_path_join (
	RoseStringObject &result,
	const char* dir, 
	const char* nm_or_dir, 
	const char* ext = 0
	);

The rose_path_join() function concatenates a directory, file name, and extension. The result is stored in the caller-provided string object and a pointer to the resulting character buffer is returned. The function ignores any null or empty input string.

A path separator will be inserted between the first and second argument if needed. The function can be used to append a directory with a filename, or to append two directories. It will avoid a double separator if the first and second arguments both have trailing/leading directory separators, such as "foo/" and "/bar" When an extension string is specified, the initial dot ('.') is optional. One will be inserted if required.

RoseStringObject path;

rose_path_join(path, foo, bar, baz);
// returns foo/bar.baz

rose_path_join(path, foo/, bar, .baz);
// returns foo/bar.baz

rose_path_join(path, foo/, bar);
// returns foo/bar

rose_path_join(path, 0, bar, baz);
// returns bar.baz

rose_path_join(path, foo/, /bar);
// returns foo/bar

rose_path_mkext()

const char * rose_path_mkext (
    RoseStringObject &result,
    const char * utf8_path,
    const char * new_ext
    );

The rose_path_mkext() function changes the file extension of a given path. The result is stored in the caller-provided string object and a pointer to the resulting character buffer is returned. As with rose_path_join, a dot separator will be added if needed.

RoseStringObject path;

rose_path_mkext(path, foo, bar);
rose_path_mkext(path, foo, .bar);
// both return foo.bar

rose_path_mkext(path, hello/world.new, old);
// returns hello/world.old

rose_path_mkext(path, hello/world.new, 0);
rose_path_mkext(path, hello/world.new, );
// both return hello/world

rose_path_search()

const char * rose_path_search (
	RoseStringObject &result,
	const char * dir, 
	const char * nm, 
	const char * ext = 0
	);

const char * rose_path_search (
	RoseStringObject &result,
	ListOfString * dirs, 
	const char * nme, 
	const char * ext = 0
	);

The rose_path_search() function finds the file path completion for a given name, directory, and possibly extension. The result is stored in the caller-provided string object and a pointer to the resulting character buffer is returned.

If multiple completions are possible, only the first match is returned. If the directory or list of directories are null, the function only looks in the current directory.

When the extension parameter is omitted or a null pointer, the function looks for a file with a known extensions (.stp, .step, etc) in a directory before a file with no extension. To only looks for files that have no extension, pass an empty string ("") for the extension.

rose_put_nested_object()

RoseBoolean rose_put_nested_object(
	RoseUnion * 	dst,
	RoseObject * 	val
	);

RoseBoolean rose_put_nested_object(
	RoseObject * 	dst,
	RoseAttribute * dst_att, 
	unsigned 	dst_idx,
	RoseObject * 	val
	);

The rose_put_nested_object() function assigns an entity instance while creating and populating intermediate RoseUnion objects as needed.

The function returns ROSE_TRUE if it was able to assign the value successfully. Otherwise, it returns ROSE_FALSE, and the select is unchanged.

The first overload takes a select instance (RoseUnion) and an object to assign. If the select already contains a value, this function will resuse as many of the intermediate selects as possible, and move any others to the trash for future deletion.

The second overload takes any type of destination object (entity, select, or aggregate), an attribute, and an index, as well as an value to assign. If the destination attribute is a select, this function will create and assign to it as with the first overload.

The attribute field is only required if the destination is an entity. It may be null for a select or aggregate. The index field is only required if the destination is an aggregate. It can be zero in other cases.

The rose_get_nested_object() function operates in the other direction to extract a value from a deeply nested set of select instances. The rose_create_select() and rose_clear_select functions are also useful.

Given the nested characterized_definition example below, we could use the following code to set a value.

// The definition of a property is a characterized_definition 
// select, which could contain:
//   characterized_object,
//   characterized_product_definition (nested select)
//       product_definition,
//       product_definition_relationship
//   product_definition_shape
//   shape_aspect, 
//   shape_aspect_relationship

RoseDesign * d
property_definition * prop;
product_definition * new_pd;

if (prop-> definition()) {
    // the top-level select exists already
    rose_put_nested_object (prop-> definition(), new_pd);
}
else {
    // create the top level object
    prop-> definition(
	 ROSE_CAST(characterized_definition, 
	     rose_create_select (
	       ROSE_DOMAIN (characterized_definition), new_pd))
	 );

    // OR create it yourself and then put
    prop-> definition (pnewIn(d) characterized_definition);
    rose_put_nested_object (prop-> definition(), new_pd);
}



// Alternatively, using the second version of the function
rose_put_nested_object (prop, prop-> getAttribute(definition), 0, new_pd);

rose_ref_get()

RoseReference * rose_ref_get(
	RoseObject * obj,
	RoseAttribute * att,
	unsigned idx = 0
	);

RoseReference * rose_ref_get(
	RoseObject * obj,
	const char * attname
	);

RoseReference * rose_ref_get(
	RoseAggregate *	obj,
	unsigned idx
	);

RoseReference * rose_ref_get(
	RoseUnion * obj
	);

The rose_ref_get() function tests whether a field of an object contains an external reference as described in References Between Data Sets. Several overloads cover use with entities, selects, and aggregates. Testing entities needs an attribute, aggregates needs an index, and selects do not need any additional information.

If the field contains an external reference, the function will return the RoseReference object that contains the URI of the reference. Typically an application might check for an unresolved reference if a field is null, but the function works regardless of whether the reference has been resolved.

The following example code shows how to test if an attribute has an associated reference.

stp_product_definition_formation * pdf;
stp_product * p = pdf-> of_product();

if (!p) {
    RoseReference * ref = rose_ref_get (pdf,of_product);
    printf (product is reference to %s\n, ref->uri());
}

rose_ref_make()

RoseReference * rose_ref_make(
	RoseDesign * design,
	const char * uri
	);

The rose_ref_make() function creates a new RoseReference instance with the given URL. The object is created in the RoseDesignSection reserved for references. Call rose_ref_put() to assign the reference as the contents of a particular object field.

See References Between Data Sets for more discussion and examples.

rose_ref_put()

RoseRefUsage * rose_ref_put(
	RoseReference * ref,
	RoseObject * obj,
	RoseAttribute * att,
	unsigned idx = 0
	);

RoseRefUsage * rose_ref_put(
	RoseReference * ref,
	RoseObject * obj,
	const char * attname
	);

RoseRefUsage * rose_ref_put(
	RoseReference * ref,
	RoseAggregate *	obj,
	unsigned idx
	);

RoseRefUsage * rose_ref_put(
	RoseReference * ref,
	RoseUnion * obj
	);

The rose_ref_put() function associates an external reference with a field of an object. Several overloads exist for entities, selects, and aggregates. Assigning to an entity needs an attribute, an aggregate needs an index, and a select does not need any additional information.

Use rose_ref_make() to create the reference object with the URI, and then assign it to a field using rose_ref_put(). This will also give the field the resolved value of the reference (if not null).

The function returns a RoseRefUsage structure which holds internal usage information. See References Between Data Sets for more discussion.

stp_product_definition_formation * pdf;

RoseReference * ref = rose_ref_make(
    pdf->design(), file://foobar.stp#anchor1
    );

rose_ref_put (ref, pdf, of_product);

rose_ref_remove()

void rose_ref_remove(
	RoseObject * obj,
	RoseAttribute * att,
	unsigned idx = 0
	);

void rose_ref_remove(
	RoseObject * obj,
	const char * attname
	);

void rose_ref_remove(
	RoseAggregate *	obj,
	unsigned idx
	);

void rose_ref_remove(
	RoseUnion * obj
	);

void rose_ref_remove(
	RoseRefUsage * obj
	);

The rose_ref_remove() function removes any association between an external reference and an object field. Use rose_ref_get() before removing if you need to work with the RoseReference object. The RoseReference object is not deleted, although it may be left without any usages.

The value of the attribute in the object is not changed. If it was null, it remains null. If it was resolved to an object pointer, it remains set to that pointer.

The RoseReference::remove_usage() function removes all uses of a reference in one operation.

rose_refcount()

unsigned long rose_refcount(
	RoseObject* obj
	);

The rose_refcount() function returns the reference count of the given object. The rose_compute_refcount() function must have been previously called to compute the reference counts for each object. This function will return zero if the counts have not been computed.

You can test if reference counts have been computed by calling rose_refcount() on a RoseDesign. The function will return a non-zero value if reference counts have previously been computed by a call to rose_compute_refcount().

See Reference Counting for more discussion.

rose_refcount_dec()

unsigned long rose_refcount_dec(
	RoseObject* obj
	);

The rose_refcount_dec() function decrements the reference count of the given object and returns the new value. If the reference count is already zero, or if reference counts have never been computed, the function just returns zero.

See Reference Counting for more discussion.

rose_refcount_dec_atts()

void rose_refcount_dec_atts(
	RoseObject* obj
	);

The rose_refcount_dec_atts() function decrements the reference count of the attributes of a given object. This does not decrement the count of the initial object, only of the objects that it points to through its attributes.

This function only follows one level of reference. A recursive version is also available as rose_refcount_recursive_dec_atts().

See Reference Counting for more discussion.

rose_refcount_inc()

unsigned long rose_refcount_inc(
	RoseObject* obj
	);

The rose_refcount_inc() function increments the reference count of the given object and returns the new value. There is no need to call rose_compute_refcount() before calling this function. An application can compute and manage reference counts on selected objects using this function if desired.

See Reference Counting for more discussion.

rose_refcount_put()

unsigned long rose_refcount_put(
	RoseObject* obj,
	unsigned long count
	);

The rose_refcount_put() function sets the reference count of the given object and returns the same count value. There is no need to call rose_compute_refcount() before calling this function. An application can compute and manage reference counts on selected objects using this function if desired.

See Reference Counting for more discussion.

rose_refcount_recursive_dec_atts()

void rose_refcount_recursive_dec_atts(
	RoseObject * obj, 
	ListOfRoseObject * return_now_unrefed = 0
	);

The rose_refcount_dec_atts() function decrements the reference count of the attributes of a given object. This continues to recursively decrement attributes of a sub-object if it becomes unreferenced. If the second parameter is used, the function will populate a list with pointers to all of the objects that becomes unreferenced as a result of the call.

This does not decrement the count of the initial object, only of the objects that it points to through its attributes.

Using this function, you could write a function to cleanly delete a tree of objects as shown below. Objects would only be deleted if they were not referenced elsewhere The counts must have been initialized by an earlier call to rose_compute_refcount().

    ListOfRoseObject objs;
    unsigned i, sz;

    rose_refcount_recursive_dec_atts(obj, &objs);
    for (i=0, sz=objs.size(); i<sz; i++) {
        rose_move_to_trash (objs[i]);
    }
    rose_move_to_trash (obj);

rose_register_substitute()

void rose_register_substitute(
	RoseObject * orig, 
	RoseObject * substitute
	);

The rose_register_substitute() function is part of the reference substitution API. This function is used to substitute one object for another and make sure that all references to the original object are updated.

First, an application calls rose_register_substitute() to specify the replacement object. Next, the original object is usually moved to the trash. When the trashcan is emptied, or rose_update_object_references() is called, pointers to the original object will be replaced by pointers to new one.

If you are using C++ classes, the new pointer must meet all C++ type compatibility constraints met by the original. The update also nulls out references to trashed or non-persistent objects. The rose_update_object_references() function will only update references in one design. Emptying the trash calls the update function on all designs and deletes all objects in the trash design.

It is not necessary to move the original object to the trash, but if it isn't, the substitution remains in effect. Any references to the object will continue to be changed whenever the trash is emptied or the update function is called.

rose_release_backptrs()

void rose_release_backptrs(
	RoseDesign * des
	);

The rose_release_backptrs() function frees the backpointers that were computed by a previous call to rose_compute_backptrs. See Backpointers for more discussion.

rose_release_refcount()

void rose_release_refcount(
	RoseDesign * des
	);

The rose_release_refcount() function clears the reference count data that was computed by a previous call to rose_compute_refcount(). This releases the memory that was used to store the reference counts. It is safe, although inefficient, to call this function multiple times, or without previously calling the compute function.

See Reference Counting for more discussion.

rose_set_cxx_schema()

void rose_set_cxx_schema(
	RoseDesign * schema
	);

void rose_set_cxx_schema_from_design(
	RoseDesign * design
	);

The rose_set_cxx_schema() functions change the RoseDomain data-dictionary entries associated with the RoseType C++ class information. The C++ class information is used by the pnew and ROSE_DOMAIN() operations.

If an application is working with schemas that have overlapping entity definitions, like many of the STEP APs, the C++ class information may be associated with data-dictionary entries from the wrong schema. This could cause incorrect behavior in traversals, the isa() function, and other areas.

The rose_set_cxx_schema() function changes all built-in C++ types to use data-dictionary entries from the given schema. The rose_set_cxx_schema_from_design() function sets the C++ class information using the schema (or schemas) of the given design.

Consider software that reads both AP203 and AP214 files. When working on either type of file, we force the C++ classes to use the appropriate domains. This is done using the set from design function.

RoseDesign * design;
design = ROSE.findDesign (AP214_datafile.stp);
rose_set_cxx_schema_from_design (design);

If we are creating a new design, we can set the schema manually using the rose_set_cxx_schema() function or we can set it from the design as before.

RoseDesign * design;
RoseDesign * schema;

/* The AP203 schema */
schema = ROSE.findDesign (config_control_design);

/* create AP203 data set */
design = new RoseDesign (AP203_datafile.stp, schema);
rose_set_cxx_schema (schema);

/* alternate approach */
design = new RoseDesign (AP203_datafile.stp, config_control_design);
rose_set_cxx_schema_from_design (design);

rose_strcasecmp / strncasecmp()

int rose_strcasecmp(
	const char * str_a, 
	const char * str_b
	);

int rose_strncasecmp(
	const char * str_a, 
	const char * str_b,
	int num
	);

The rose_strcasecmp() and rose_strncasecmp() functions are used internally by the ROSE library. They perform string comparison in the manner of strcmp() but as if the input strings were converted to all lowercase. The rose_strncasecmp() function compares a fixed number of characters in the style of strncmp().

These functions ignore the current locale settings and only convert case for the 7bit characters A-Z and a-z. Any high-bit UTF8 or ANSI characters are compared verbatim. The functions also treat null pointers as an empty string ("") for comparison.

Note that the rose_strcmp_as_lower() function is just an alias for rose_strcasecmp().

rose_strcenter()

char * rose_strcenter(
	char * buf,
	const char * str,
	size_t bufsz
	);

The rose_strcenter() functions is a simple string utility that centers a string in a buffer of a given size. The first argument is the buffer to be filled, the second is the string to fill it with and the last is the size of the buffer. The function returns a pointer to the buffer. The input buffer and source strings must not be in overlapping memory.

rose_strcmp_as_lower / as_upper()

int rose_strcmp_as_lower(
	const char * str_a, 
	const char * str_b
	);

int rose_strcmp_as_upper(
	const char * str_a, 
	const char * str_b
	);

The rose_strcmp_as_lower() and rose_strcmp_as_upper() functions are used internally by the ROSE library. They perform string comparison in the manner of strcmp() but as if the input strings were converted to all lowercase or all uppercase characters, respectively.

These functions ignore the current locale settings and only convert case for the 7bit characters A-Z and a-z. Any high-bit UTF8 or ANSI characters are compared verbatim. The functions also treat null pointers as an empty string ("") for comparison.

rose_string_to_enum()

RoseEnum rose_string_to_enum(
	const char * str,
	RoseAttribute * att
	);

RoseEnum rose_string_to_enum(
	const char * str,
	RoseTypePtr& slottype
	);

The rose_string_to_enum() function searches the C++ type information finds the numeric value from string enumerator. The function returns ROSE_NULL_ENUM if string value is null or does not match any of the enumerators. The search ignores case and recognizes "$" as a null value. It also recognizes "NULL" as ROSE_NULL_ENUM if the enum does not already contain an enumerator with that name.

See rose_enum_to_string() to convert values in the other direction.

rose_strtolower / strtoupper()

char * rose_strtolower(
	char * str
	);

char * rose_strtoupper(
	char * str
	);

The rose_strtolower() and rose_strtoupper() functions are used internally by the ROSE library. These simple string utility functions convert the contents of a string to all lowercase or all uppercase characters, respectively.

These functions ignore the current locale settings and only convert case for the 7bit characters A-Z and a-z. Any high-bit UTF8 or ANSI characters are left unchanged.

The functions return the string pointer that was passed in. They will also tolerate a null pointer as input.

rose_trash()

RoseDesign * rose_trash();

The rose_trash() function returns a pointer to the trash design. The trash design contains objects scheduled for deletion. Persistent objects can be moved to the trash using the rose_move_to_trash() function, or by using RoseObject::move() with the trash design pointer.

RoseDesign * d;
Point * pt = pnewIn(d) Point;

rose_move_to_trash (pt);
pt-> move (rose_trash());    /* equivalent */

See Also

Deleting Objects; rose_empty_trash(); rose_move_to_trash()

rose_update_object_references()

void rose_update_object_references(
	RoseDesign * design
	);

The rose_update_object_references() function examines every attribute of every object in one specific design. The function expands all reference substitutions that have been put in place by either rose_register_substitute() or rose_mutate(), and nulls out references to trashed or non-persistent objects.

The rose_empty_trash() function performs the same operation on all designs in memory.

rose_xcopy()

RoseObject * rose_xcopy(
	RoseDesign * dst,
	RoseObject * src,
	unsigned flags=0
	);

void rose_xcopy(
	RoseDesign * dst,
	ListOfRoseObject &objs,
	unsigned flags=0
	);

The rose_xcopy() function copies objects and keeps associativity to those copies, so that networks of objects can be constructed iteratively. It also treats selects and aggregates as second-class objects that are never shared, which makes sense when working with the structures found in STEP models.

Each call to rose_xcopy() will reuse previously copied objects until you call rose_xcopy_done(). The behavior can be adjusted with the bit flags described below. You can find the latest copy of a source object with rose_xcopy_get_dst() or the source of a copied object with rose_xcopy_get_src(). If you have instructed the function to make multiple copies, you can work through all of them by calling rose_xcopy_get_next_dst() until it returns NULL.

Two versions are available, one which copies an single object and returns the new value, and another which iteratively copies a list of objects and returns void. By default, the functions will not make another copy of an input (object or list element) that has already been copied, and will fill the object attributes of that input with existing copies or null. Primitive values (strings, numbers, booleans) are always copied.

The behavior can be adjusted by the following bit flags:

ROSE_XCOPY_FOLLOW
Recursively follow object attribute references. Fill them with a previous copy or make a new recursive copy.
ROSE_XCOPY_MULTIPLE
Create a new copy of an object each time called, otherwise just reuse the last copy. This will only create one additional copy of a given object per call.
ROSE_XCOPY_ADD_ALL
When copying an aggregate object, add all copies to it rather than just the most recent. This is useful when making multiple copies that should all be part of some STEP applied-style list of objects.
ROSE_XCOPY_PATH
Make a multiple copy of any object that is passed as input, and use the new copy in any attribute value. Like is like multiple but does not use any previously copied value in attributes, only a new copy or the source attribute value.
RoseDesign * src;
RoseDesign * dst;
ListOfRoseObject objs;

// copy entire tree of objects to destination
rose_xcopy(dst, objs, ROSE_XCOPY_FOLLOW);

// make several shallow copies to destination
rose_xcopy(dst, objs, ROSE_XCOPY_MULTIPLE);
rose_xcopy(dst, objs, ROSE_XCOPY_MULTIPLE);
rose_xcopy(dst, objs, ROSE_XCOPY_MULTIPLE);

// make another deep copy in destination 
rose_xcopy(dst, objs, ROSE_XCOPY_MULTIPLE | ROSE_XCOPY_FOLLOW);

rose_xcopy_done(src, dst);

rose_xcopy_done()

void rose_xcopy_done(
	RoseDesign * src,
	RoseDesign * dst = 0
	);

The rose_xcopy_done() function finishes an iterative copy session by removing all associativity information from previous calls to rose_xcopy(). A new call to rose_xcopy() will make new copies and will not know about any copies made prior to calling rose_xcopy_done(). The arguments are the source and destination designs, or just a single design if you happen to be copying within a design. The order does not matter - it does the same thing to each design.

Copying will work across more than two designs, such as copying objects from many to one. In such a case, you can just call the done function on each of the designs individually.

rose_xcopy_get_dst()/next_dst()

RoseObject * rose_xcopy_get_dst(
	RoseObject * src
	);
	
RoseObject * rose_xcopy_get_next_dst(
	RoseObject * dst
	);

The rose_xcopy_get_dst() function gets the most recent destination copy when given a source object, or NULL if no copy has been made. When making multiple copies of an object, iteratively calling rose_xcopy_get_next_dst() will return the earlier copies, or NULL if no more exist.

RoseObject * src;
RoseObject * obj = rose_xcopy_get_dst(src);
if (!obj) return;   // not copied

printf(Object copied\n);

// note if we have additional copies
while ( (obj=rose_xcopy_get_next_dst(obj)) != 0)
{
    printf(Object copied again\n);
}

rose_xcopy_get_src()

RoseObject * rose_xcopy_get_src(
	RoseObject * dst
	);

The rose_xcopy_get_src() function returns the source object for a copied object, or NULL if the object is not a copy.