static void
test_application (Accessible *application)
{
	char *str;

	fprintf (stderr, "Testing application ...\n");
	g_assert (Accessible_isApplication (application));
	g_assert (Accessible_getApplication (application) ==
		  application);
	AccessibleApplication_unref (application);

	str = AccessibleApplication_getToolkitName (application);
	g_assert (str != NULL);
	g_assert (!strcmp (str, "GAIL"));
	SPI_freeString (str);

	str = AccessibleApplication_getLocale (application, LC_MESSAGES);
	g_assert (!strcmp (str, setlocale (LC_MESSAGES, NULL)));
        SPI_freeString (str);

	str = AccessibleApplication_getVersion (application);
	g_assert (str != NULL);
	SPI_freeString (str);

	AccessibleApplication_getID (application);
}
static void
test_editable_text (AccessibleEditableText *etext)
{
	char *str;
	AccessibleText *text;

	fprintf (stderr, "Testing editable text ...\n");
	
	g_assert (Accessible_isText (etext));
	text = Accessible_getText (etext);

	AccessibleEditableText_setTextContents (
		etext, TEST_STRING_B);

	str = AccessibleText_getText (text, 0, WHOLE_STRING);
	g_assert (!strcmp (str, TEST_STRING_B));

	SPI_freeString (str);

	/* FIXME: lots more editing here */

	AccessibleEditableText_setTextContents (
		etext, TEST_STRING_A);

	AccessibleText_unref (text);
}
Ejemplo n.º 3
0
static void restartTerm(Accessible *newTerm, AccessibleText *newTextTerm) {
  char *c,*d;
  const char *e;
  long i,len;
  char *text;

  if (curFocus)
    finiTerm();
  Accessible_ref(curFocus = newTerm);
  curTerm = newTextTerm;
  logMessage(LOG_DEBUG,"new term %p",curTerm);
  text = AccessibleText_getText(curTerm,0,LONG_MAX);
  curNumRows = 0;
  if (curRows) {
    for (i=0;i<curNumRows;i++)
      free(curRows[i]);
    free(curRows);
  }
  free(curRowLengths);
  c = text;
  while (*c) {
    curNumRows++;
    if (!(c = strchr(c,'\n')))
      break;
    c++;
  }
  logMessage(LOG_DEBUG,"%ld rows",curNumRows);
  curRows = malloc(curNumRows * sizeof(*curRows));
  curRowLengths = malloc(curNumRows * sizeof(*curRowLengths));
  i = 0;
  curNumCols = 0;
  for (c = text; *c; c = d+1) {
    d = strchr(c,'\n');
    if (d)
      *d = 0;
    e = c;
    curRowLengths[i] = (len = my_mbsrtowcs(NULL,&e,0,NULL)) + (d != NULL);
    if (len > curNumCols)
      curNumCols = len;
    else if (len < 0) {
      if (len==-2)
	logMessage(LOG_ERR,"unterminated sequence %s",c);
      else if (len==-1)
	logSystemError("mbrlen");
      curRowLengths[i] = (len = -1) + (d != NULL);
    }
    curRows[i] = malloc((len + (d!=NULL)) * sizeof(*curRows[i]));
    e = c;
    my_mbsrtowcs(curRows[i],&e,len,NULL);
    if (d)
      curRows[i][len]='\n';
    else
      break;
    i++;
  }
  logMessage(LOG_DEBUG,"%ld cols",curNumCols);
  SPI_freeString(text);
  caretPosition(AccessibleText_getCaretOffset(curTerm));
}
Ejemplo n.º 4
0
static void
log_accessible (EventLog *log, Accessible *accessible)
{
	GtkTextTag *tag;
	GtkTextIter iter;
	char *text, *name, *descr, *short_descr;
	char *role_name, *ifaces;

	if (!accessible) {
		log_message (log, "<Null>");
		return;
	}

	tag = gtk_text_buffer_create_tag (log->log_text, NULL, 
					  "foreground", "blue", 
					  "underline", PANGO_UNDERLINE_SINGLE, 
					  NULL);
	Accessible_ref (accessible);
	g_object_set_data_full (G_OBJECT (tag), "accessible", accessible,
				(GDestroyNotify) Accessible_unref );

	ifaces = accessible_get_iface_string (accessible);
	role_name = Accessible_getRoleName (accessible);
	name = Accessible_getName (accessible);
	descr = Accessible_getDescription (accessible);
	short_descr = ellipsize (descr);

	/* FIXME: nice mangled printout of supported interfaces ? */
	text = g_strdup_printf ("%s:%s:%s:%s",
				ifaces,
				role_name ? role_name : "--",
				name ? name : "--",
				short_descr ? short_descr : "--");

	gtk_text_buffer_get_end_iter (log->log_text, &iter);
	gtk_text_buffer_insert_with_tags (log->log_text, &iter, text, -1, tag, NULL);

	g_free (text);
	g_free (short_descr);
	SPI_freeString (descr);
	SPI_freeString (name);
	SPI_freeString (role_name);
	g_free (ifaces);

	log_track_end (log);
}
Ejemplo n.º 5
0
static void
control_spi_listener_build_actions_list (ControlSpiListener *listener, Accessible *parent, int depth)
{
    Accessible* child;
    AccessibleRole role;

    int i, child_count;

    if (depth > SEARCH_DEPTH)
        return;

    child_count = Accessible_getChildCount (parent);

    child_count = MIN (child_count, SEARCH_BREADTH);

    for (i = 0; i < child_count; ++i) {
        char *name;
        char *normalized_name;

        child = Accessible_getChildAtIndex (parent, i);

        if (child == parent)
            continue;

        name = Accessible_getName (child);

#if DEBUG
        {
            gchar *role_name;

            role_name = Accessible_getRoleName (child);
            g_message ("Looking at %s %s", role_name, name);
        }
#endif

        if (name) {
            normalized_name = control_spi_listener_normalize (name);
            if (normalized_name && strlen(normalized_name) > 0 && is_actionable (child)) {
                AccessibleItem *item;

                item = g_new0(AccessibleItem, 1);
                Accessible_ref (child);
                item->accessible = child;
                item->name = g_strdup (normalized_name);

                listener->actions = g_slist_append (listener->actions, item);
            }
            SPI_freeString (name);
            g_free (normalized_name);
        }

        if (is_worth_searching (child))
            control_spi_listener_build_actions_list (listener, child, depth+1);

        Accessible_unref (child);
    }
}
static void
stream_cache_item_free (gpointer a)
{
  struct StreamCacheItem *cache_item = a;

  cspi_release_unref (cache_item->stream);
  SPI_freeString (cache_item->mimetype);
  g_free (cache_item);
}
static void
test_misc (void)
{
	fprintf (stderr, "Testing misc bits ...\n");

	g_assert (!Accessible_isComponent (NULL));
	g_assert (Accessible_getComponent (NULL) == NULL);
	SPI_freeString (NULL);
}
Ejemplo n.º 8
0
void
log_object_property_change (EventLog *log, const AccessibleEvent *event)
{
	char *detail;

	if (!log_sanity_check (log, event, SANITY_NOCHECK_SOURCE) )
		return;

	{
		char **split = g_strsplit (event->type, ":", -1);
		if (split && split[0] && split[1] && split[2])
			detail = g_strdup (split[2]);
		else
			detail = g_strdup ("");
		g_strfreev (split);
	}

	if (!strcmp (detail, "accessible-name")) {
		char *text = AccessibleNameChangedEvent_getNameString (event);
		log_string_prop_change (log, event, "name", text);
		SPI_freeString (text);

	} else if (!strcmp (detail, "accessible-description")) {
		char *text = AccessibleDescriptionChangedEvent_getDescriptionString (event);
		log_string_prop_change (log, event, "description", text);
		SPI_freeString (text);

	} else if (!strcmp (detail, "accessible-parent")) {
		Accessible *parent = AccessibleParentChangedEvent_getParentAccessible (event);
		log_message (log, "parent change %d %d on ", event->detail1, event->detail2);
		log_accessible (log, event->source);
		log_message (log, " to parent: ");
		log_accessible (log, parent);
		log_message (log, "\n");
		
		Accessible_unref (parent);
 	} else {
		log_message (log, "generic property change (%s) %d %d on ",
			     event->type, event->detail1, event->detail2);
		log_accessible (log, event->source);
		log_message (log, "\n");
	}
	g_free (detail);
}
Ejemplo n.º 9
0
static void check_for_matching_frame( Driver* dp, Accessible* accessible ) {
    int role = Accessible_getRole( accessible );
    if ( role == SPI_ROLE_FRAME ) {
        char* frame_name = Accessible_getName( accessible );
        if ( strcmp(frame_name, dp->application_title) == 0 ) {
            dp->frame = accessible;
            dp->found_application = TRUE;
        }
        SPI_freeString( frame_name );
    }
}
Ejemplo n.º 10
0
static gboolean
eval_func (Accessible *a, gpointer data)
{
    gboolean found;
    char *name;

    name = Accessible_getName (a);
    found = g_str_equal (name, "Window List");
    SPI_freeString (name);

    return found;
}
static void
test_action (AccessibleAction *action)
{
	gint n_actions, i;
	gchar *s, *sd;
	g_assert ((n_actions = AccessibleAction_getNActions (action)) >= 0);

	fprintf (stderr, "Testing actions...");
	for (i = 0; i < n_actions; ++i)
	{
		s = AccessibleAction_getName (action, i);
		g_assert (s);
		sd = AccessibleAction_getDescription (action, i);
		g_assert (sd);
		fprintf (stderr, "%d: %s (%s);  ", i, s, sd);
		SPI_freeString (s);
		SPI_freeString (sd);
		g_assert (AccessibleAction_doAction (action, i));
	}
	fprintf (stderr, "\n");
}
static void
test_text (AccessibleText *text)
{
	char *str;

	fprintf (stderr, "Testing text ...\n");

	g_assert (AccessibleText_getCharacterCount (text) ==
		  strlen (TEST_STRING_A));

	str = AccessibleText_getText (text, 0, WHOLE_STRING);
	g_assert (!strcmp (str, TEST_STRING_A));
	SPI_freeString (str);

	str = AccessibleText_getText (text, 0, 5);
	g_assert (!strncmp (str, TEST_STRING_A, 5));
	SPI_freeString (str);

	AccessibleText_setCaretOffset (text, 7);
	g_assert (AccessibleText_getCaretOffset (text) == 7);

	/* FIXME: lots more tests - selections etc. etc. */
}
Ejemplo n.º 13
0
void
log_object_text_changed (EventLog *log, const AccessibleEvent *event)
{
	char *text;
	if (!log_sanity_check_text (log, event))
		return;

	log_message (log, "text changed (%s) offset %d length %d on ",
		     event->type, event->detail1, event->detail2);
	log_accessible (log, event->source);

	text = AccessibleTextChangedEvent_getChangeString (event);
	log_message (log, " change string '%s'", text ? text : "<null>");
	SPI_freeString (text);
}
Ejemplo n.º 14
0
static SPIBoolean exception_handler( SPIException* err, SPIBoolean is_fatal ) {
    // We wish to swallow a non-fatal error...
    if ( is_fatal )
        return FALSE;       // We haven't dealt with it.

    // ...which has a specific description.
    char* description = SPIException_getDescription( err );
    int result = strcmp( description, "IDL:omg.org/CORBA/COMM_FAILURE:1.0" );
    SPI_freeString( description );

    if ( result != 0 )
        return FALSE;       // We haven't dealt with it.
    else
        return TRUE;        // We have dealt with it -- ie ignore it.
}
static void
test_image (AccessibleImage *image)
{
	char *desc;
	long int x = -1, y = -1, width = -1, height = -1;

	desc = AccessibleImage_getImageDescription (image);
	g_assert (desc != NULL);
	SPI_freeString (desc);

	AccessibleImage_getImagePosition (image, &x, &y,
					  SPI_COORD_TYPE_SCREEN);
	AccessibleImage_getImageSize     (image, &width, &height);
	AccessibleImage_getImageExtents  (image, &x, &y, &width, &height,
					  SPI_COORD_TYPE_WINDOW);
}
Ejemplo n.º 16
0
void
log_object_text_selection_changed (EventLog *log, const AccessibleEvent *event)
{
	char *text;
	if (!log_sanity_check_text (log, event))
		return;

	/* FIXME: more detail on the details */
	log_message (log, "text selection changed (%s) %d %d on ",
		     event->type, event->detail1, event->detail2);
	log_accessible (log, event->source);

	text = AccessibleTextSelectionChangedEvent_getSelectionString (event);
	log_message (log, "context '%s'\n", text);
	SPI_freeString (text);
}
Ejemplo n.º 17
0
void
log_window (EventLog *log, const AccessibleEvent *event)
{
	char *title;

	if (!log_sanity_check (log, event, SANITY_CHECK_SOURCE) )
		return;

	log_message (log, "window event '%s' (%d) (%d) on ",
		     event->type, event->detail1, event->detail2);
	log_accessible (log, event->source);

	title = AccessibleWindowEvent_getTitleString (event);
	log_message (log, " with title '%s'\n", title ? title : "<Null>");
	SPI_freeString (title);
}
Ejemplo n.º 18
0
static void
report_leaked_ref (gpointer key, gpointer val, gpointer user_data)
{
  char *name, *role;
  Accessible *a = (Accessible *) val;
  
  name = Accessible_getName (a);
  if (cspi_exception ())
    {
      name = NULL;
    }

  role = Accessible_getRoleName (a);
  if (cspi_exception ())
    {
      role = NULL;
    }

  fprintf (stderr, "leaked %d references to object %s, role %s %p\n",
	   a->ref_count, name ? name : "<?>", role ? role : "<?>", a);

  SPI_freeString (name);
}
static void
validate_accessible (Accessible *accessible,
		     gboolean    has_parent,
		     gboolean    recurse_down)
{
	Accessible          *tmp;
	char                *name, *descr;
	AccessibleRole       role;
	AccessibleRelation **relations;
	char                *role_name;
	GString             *item_str = g_string_new ("");
	int                  i;

	name = Accessible_getName (accessible);
	g_assert (name != NULL);
	
	descr = Accessible_getDescription (accessible);
	g_assert (descr != NULL);

	role = Accessible_getRole (accessible);
	g_assert (role != SPI_ROLE_INVALID);
	role_name = Accessible_getRoleName (accessible);
	g_assert (role_name != NULL);

	relations = Accessible_getRelationSet (accessible);
	g_assert (relations != NULL);

	for (i = 0; relations [i]; i++) {
		AccessibleRelationType type;
		int                    targets;

		fprintf (stderr, "relation %d\n", i);

		type = AccessibleRelation_getRelationType (relations [i]);
		g_assert (type != SPI_RELATION_NULL);

		targets = AccessibleRelation_getNTargets (relations [i]);
		g_assert (targets != -1);

		AccessibleRelation_unref (relations [i]);
		relations [i] = NULL;
	}
	free (relations);

	if (print_tree) {
		int i;

		for (i = 0; i < print_tree_depth; i++)
			fputc (' ', stderr);
		fputs ("|-> [ ", stderr);
	}

	if (Accessible_isAction (accessible)) {
		tmp = Accessible_getAction (accessible);
		g_assert (tmp != NULL);
		if (print_tree)
			fprintf (stderr, "At");
		else
			test_action (tmp);
		AccessibleAction_unref (tmp);
	}

	if (Accessible_isApplication (accessible)) {
		tmp = Accessible_getApplication (accessible);
		if (print_tree)
			fprintf (stderr, "Ap");
		else
			test_application (tmp);
		AccessibleApplication_unref (tmp);
	}

	if (Accessible_isComponent (accessible)) {
		tmp = Accessible_getComponent (accessible);
		g_assert (tmp != NULL);
		if (print_tree)
			fprintf (stderr, "Co");
		else
			test_component (tmp);
		AccessibleComponent_unref (tmp);
	}

	if (Accessible_isEditableText (accessible)) {
		tmp = Accessible_getEditableText (accessible);
		g_assert (tmp != NULL);
		if (print_tree)
			fprintf (stderr, "Et");
		else
			test_editable_text (tmp);
		AccessibleEditableText_unref (tmp);
	}

	if (Accessible_isHypertext (accessible)) {
		tmp = Accessible_getHypertext (accessible);
		g_assert (tmp != NULL);
		if (print_tree)
			fprintf (stderr, "Ht");
		AccessibleHypertext_unref (tmp);
	}

	if (Accessible_isImage (accessible)) {
		tmp = Accessible_getImage (accessible);
		g_assert (tmp != NULL);
		if (print_tree) {
			char *desc;

			fprintf (stderr, "Im");

			desc = AccessibleImage_getImageDescription (tmp);
			g_string_append_printf (
				item_str, " image descr: '%s'", desc);
			SPI_freeString (desc);
		} else
			test_image (tmp);

		AccessibleImage_unref (tmp);
	}

	if (Accessible_isSelection (accessible)) {
		tmp = Accessible_getSelection (accessible);
		g_assert (tmp != NULL);
		if (print_tree)
			fprintf (stderr, "Se");
		AccessibleSelection_unref (tmp);
	}

	if (Accessible_isTable (accessible)) {
		tmp = Accessible_getTable (accessible);
		g_assert (tmp != NULL);
		if (print_tree)
			fprintf (stderr, "Ta");
		else
			test_table (tmp);
		AccessibleTable_unref (tmp);
	}

	if (Accessible_isText (accessible)) {
		tmp = Accessible_getText (accessible);
		g_assert (tmp != NULL);
		if (print_tree)
			fprintf (stderr, "Te");
		else {
			if (strcmp (name, TEST_STRING_A_OBJECT) == 0)	
				test_text (tmp);
		}
		AccessibleText_unref (tmp);
	}

	if (Accessible_isValue (accessible)) {
		tmp = Accessible_getValue (accessible);
		g_assert (tmp != NULL);
		if (print_tree)
			fprintf (stderr, "Va");
		else
			test_value (tmp); 
		AccessibleValue_unref (tmp);
	}

	if (print_tree)
		fprintf (stderr, " ] '%s' (%s) - %s: %s\n",
			 name, descr, role_name, item_str->str);

	SPI_freeString (name);
	SPI_freeString (descr);
	SPI_freeString (role_name);
	g_string_free (item_str, TRUE);

	validate_tree (accessible, has_parent, recurse_down);
}
Ejemplo n.º 20
0
static void evListenerCB(const AccessibleEvent *event, void *user_data) {
  static int running = 0;
  struct evList *ev = malloc(sizeof(*ev));
  AccessibleEvent_ref(event);
  AccessibleText *newText;
  ev->next = evs;
  ev->ev = event;
  evs = ev;
  int state_changed_focused;

  /* this is not atomic but we can only be recursively called within calls
   * to the lib */
  if (running)
    return;
  else
    running = 1;

  while (evs) {
    pthread_mutex_lock(&updateMutex);
    /* pickup a list of events to handle */
    ev = evs;
    evs = NULL;
    for (; ev; AccessibleEvent_unref(ev->ev), ev = ev->next) {
      event = ev->ev;
      state_changed_focused = !strcmp(event->type,"object:state-changed:focused");
      if (state_changed_focused && !event->detail1) {
	if (event->source == curFocus)
	  finiTerm();
      } else if (!strcmp(event->type,"focus:") || (state_changed_focused && event->detail1)) {
	if (!(newText = Accessible_getText(event->source))) {
	  if (curFocus) finiTerm();
	} else {
          AccessibleRole role = Accessible_getRole(event->source);
	  if (typeAll ||
	      (typeText && ((role == SPI_ROLE_TEXT) || (role == SPI_ROLE_PASSWORD_TEXT) || (role == SPI_ROLE_PARAGRAPH))) ||
	      (typeTerminal && (role == SPI_ROLE_TERMINAL))) {
	    restartTerm(event->source, newText);
	  } else {
	    logMessage(LOG_DEBUG,"AT SPI widget not for us");
	    if (curFocus) finiTerm();
	  }
	}
      } else if (!strcmp(event->type,"object:text-caret-moved")) {
	if (event->source != curFocus) continue;
	logMessage(LOG_DEBUG,"caret move to %lu",event->detail1);
	caretPosition(event->detail1);
      } else if (!strcmp(event->type,"object:text-changed:delete")) {
	long x,y,toDelete = event->detail2;
	long length = 0, toCopy;
	long downTo; /* line that will provide what will follow x */
	logMessage(LOG_DEBUG,"delete %lu from %lu",event->detail2,event->detail1);
	if (event->source != curFocus) continue;
	findPosition(event->detail1,&x,&y);
	downTo = y;
	if (downTo < curNumRows)
		length = curRowLengths[downTo];
	while (x+toDelete >= length) {
	  downTo++;
	  if (downTo <= curNumRows - 1)
	    length += curRowLengths[downTo];
	  else {
	    /* imaginary extra line doesn't provide more length, and shouldn't need to ! */
	    if (x+toDelete > length) {
	      logMessage(LOG_ERR,"deleting past end of text !");
	      /* discarding */
	      toDelete = length - x;
	    }
	    break; /* deleting up to end */
	  }
	}
	if (length-toDelete>0) {
	  /* still something on line y */
	  if (y!=downTo) {
	    curRowLengths[y] = length-toDelete;
	    curRows[y]=realloc(curRows[y],curRowLengths[y]*sizeof(*curRows[y]));
	  }
	  if ((toCopy = length-toDelete-x))
	    memmove(curRows[y]+x,curRows[downTo]+curRowLengths[downTo]-toCopy,toCopy*sizeof(*curRows[downTo]));
	  if (y==downTo) {
	    curRowLengths[y] = length-toDelete;
	    curRows[y]=realloc(curRows[y],curRowLengths[y]*sizeof(*curRows[y]));
	  }
	} else {
	  /* kills this line as well ! */
	  y--;
	}
	if (downTo>=curNumRows)
	  /* imaginary extra lines don't need to be deleted */
	  downTo=curNumRows-1;
	delRows(y+1,downTo-y);
	caretPosition(AccessibleText_getCaretOffset(curTerm));
      } else if (!strcmp(event->type,"object:text-changed:insert")) {
	long len=event->detail2,semilen,x,y;
	char *added;
	const char *adding,*c;
	logMessage(LOG_DEBUG,"insert %lu from %lu",event->detail2,event->detail1);
	if (event->source != curFocus) continue;
	findPosition(event->detail1,&x,&y);
	adding = c = added = AccessibleTextChangedEvent_getChangeString(event);
	if (x && (c = strchr(adding,'\n'))) {
	  /* splitting line */
	  addRows(y,1);
	  semilen=my_mbslen(adding,c+1-adding);
	  curRowLengths[y]=x+semilen;
	  if (x+semilen-1>curNumCols)
	    curNumCols=x+semilen-1;

	  /* copy beginning */
	  curRows[y]=malloc(curRowLengths[y]*sizeof(*curRows[y]));
	  memcpy(curRows[y],curRows[y+1],x*sizeof(*curRows[y]));
	  /* add */
	  my_mbsrtowcs(curRows[y]+x,&adding,semilen,NULL);
	  len-=semilen;
	  adding=c+1;
	  /* shift end */
	  curRowLengths[y+1]-=x;
	  memmove(curRows[y+1],curRows[y+1]+x,curRowLengths[y+1]*sizeof(*curRows[y+1]));
	  x=0;
	  y++;
	}
	while ((c = strchr(adding,'\n'))) {
	  /* adding lines */
	  addRows(y,1);
	  semilen=my_mbslen(adding,c+1-adding);
	  curRowLengths[y]=semilen;
	  if (semilen-1>curNumCols)
	    curNumCols=semilen-1;
	  curRows[y]=malloc(semilen*sizeof(*curRows[y]));
	  my_mbsrtowcs(curRows[y],&adding,semilen,NULL);
	  len-=semilen;
	  adding=c+1;
	  y++;
	}
	if (len) {
	  /* still length to add on the line following it */
	  if (y==curNumRows) {
	    /* It won't insert ending \n yet */
	    addRows(y,1);
	    curRows[y]=NULL;
	    curRowLengths[y]=0;
	  }
	  curRowLengths[y] += len;
	  curRows[y]=realloc(curRows[y],curRowLengths[y]*sizeof(*curRows[y]));
	  memmove(curRows[y]+x+len,curRows[y]+x,(curRowLengths[y]-(x+len))*sizeof(*curRows[y]));
	  my_mbsrtowcs(curRows[y]+x,&adding,len,NULL);
	  if (curRowLengths[y]-(curRows[y][curRowLengths[y]-1]=='\n')>curNumCols)
	    curNumCols=curRowLengths[y]-(curRows[y][curRowLengths[y]-1]=='\n');
	}
	SPI_freeString(added);
	caretPosition(AccessibleText_getCaretOffset(curTerm));
      } else
	logMessage(LOG_INFO,"event %s, source %p, detail1 %lu detail2 %lu",event->type,event->source,event->detail1,event->detail2);
    }
    pthread_mutex_unlock(&updateMutex);
  }
  running = 0;
}
Ejemplo n.º 21
0
char * windows_string ( char * _str )
{
    char * ret = SQ_STRDUP_FUNCTION(_str);
    SPI_freeString ( _str );
    return ret;
}