コード例 #1
0
ファイル: fibstr.c プロジェクト: R0maNNN/study
char *get_fibstr(char **a, char **b, int *len_a, int *len_b, int n) {
	int i;
	char *foo;
	for (i = 1; i < n; i++) {
		foo = concat(*a, *b, *len_a, *len_b);
		num_swap(len_b, len_a);
		*len_b += *len_a;
		str_swap(b, a);
		str_swap(b, &foo);
		free(foo);
	}
	return *a;
}
コード例 #2
0
int dci_load(struct dci_state* state, struct dc_entry_t* entry)
{
	if(entry->cached == 0)
	{
		struct str_t uri;
		str_init_create(&uri, getfile_uri, 0);

		const struct str_t const* uri_parts[] =
		{
			&slash,
			&entry->_id,
		};
		str_concat(&uri, sizeof(uri_parts)/sizeof(const struct str_t const*), uri_parts);
		{
			struct request_t request;
			ci_init(&request, &uri, 0, NULL, NULL, GET);
			ci_request(&request);
		
			str_swap(&request.response.body, &entry->cache);
			ci_destroy(&request);
			entry->cached = 1;
		}
	}

	return 0;
}
コード例 #3
0
static str *call_request_lookup_tcp(char **out, struct callmaster *m, enum call_opmode opmode) {
	struct call *c;
	struct call_monologue *monologue;
	GQueue s = G_QUEUE_INIT;
	str *ret = NULL, callid, fromtag, totag = STR_NULL;
	GHashTable *infohash;

	str_init(&callid, out[RE_TCP_RL_CALLID]);
	infohash = g_hash_table_new_full(g_str_hash, g_str_equal, free, free);
	c = call_get_opmode(&callid, m, opmode);
	if (!c) {
		ilog(LOG_WARNING, "["STR_FORMAT"] Got LOOKUP for unknown call-id", STR_FMT(&callid));
		goto out;
	}

	info_parse(out[RE_TCP_RL_INFO], infohash, m);
	streams_parse(out[RE_TCP_RL_STREAMS], m, &s);
	str_init(&fromtag, g_hash_table_lookup(infohash, "fromtag"));
	if (!fromtag.s) {
		ilog(LOG_WARNING, "No from-tag in message");
		goto out2;
	}
	str_init(&totag, g_hash_table_lookup(infohash, "totag"));
	if (opmode == OP_ANSWER) {
		if (!totag.s) {
			ilog(LOG_WARNING, "No to-tag in message");
			goto out2;
		}
		str_swap(&fromtag, &totag);
	}

	monologue = call_get_mono_dialogue(c, &fromtag, &totag, NULL);
	if (!monologue) {
		ilog(LOG_WARNING, "Invalid dialogue association");
		goto out2;
	}
	if (monologue_offer_answer(monologue, &s, NULL))
		goto out2;

	ret = streams_print(&monologue->active_dialogue->medias, 1, s.length, NULL, SAF_TCP);

out2:
	rwlock_unlock_w(&c->master_lock);
	streams_free(&s);

	if (m->conf.redis_write) {
		redis_update(c, m->conf.redis_write, ANY_REDIS_ROLE);
	} else if (m->conf.redis) {
		redis_update(c, m->conf.redis, MASTER_REDIS_ROLE);
	}

	ilog(LOG_INFO, "Returning to SIP proxy: "STR_FORMAT"", STR_FMT0(ret));
	obj_put(c);

out:
	g_hash_table_destroy(infohash);
	return ret;
}
コード例 #4
0
ファイル: p1.c プロジェクト: medium-endian/GDIMES
void stringBubbleSort(int n, char **s) {
  int comp;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n - i - 1; j++) {

      comp = my_strcmp(s[j], s[j + 1]);
      if (comp > 0) {
        str_swap(&s[j], &s[j + 1]);
      }
    }
  }
}
コード例 #5
0
ファイル: 3.c プロジェクト: isseium/IPU-Softy-PracB
int main()
{
    char a[80], b[80]; /* 2つの文字配列 */

    /* 文字列を入力 */
    printf("a: ");
    scanf("%s", a);
    printf("b: ");
    scanf("%s", b);

    str_swap(a, b); /* 文字列をコピー */
    printf("a: %s\n", a);
    printf("b: %s\n", b); /* コピー後の結果を表示 */

    return 0;
}
コード例 #6
0
ファイル: engine.cpp プロジェクト: sunfirefox/yb-orm
void
EngineBase::gen_sql_delete(String &sql, TypeCodes &type_codes_out,
        const Table &table, const SqlGeneratorOptions &options)
{
    if (!table.pk_fields().size())
        throw BadSQLOperation(_T("cannot build update statement: no key in table"));
    SqlGeneratorContext ctx;
    String sql_query = _T("DELETE FROM ") + table.name();
    TypeCodes type_codes;
    Key sample_key;
    table.mk_sample_key(type_codes, sample_key);
    sql_query += _T(" WHERE ")
        + KeyFilter(sample_key).generate_sql(options, &ctx);
    type_codes_out.swap(type_codes);
    str_swap(sql, sql_query);
}
コード例 #7
0
ファイル: str_swa_b.c プロジェクト: her0m31/Studys
int main()
{
  char str1[80], str2[80];
  
  printf("Input a string1: ");
  scanf("%s", str1);

  printf("Input a string2: ");
  scanf("%s", str2);

  str_swap(str1, str2);

  printf("string1: %s\n", str1);

  printf("string2: %s\n", str2);

  return 0;
}
コード例 #8
0
ファイル: engine.cpp プロジェクト: sunfirefox/yb-orm
void
EngineBase::gen_sql_update(String &sql, TypeCodes &type_codes_out,
        ParamNums &param_nums_out, const Table &table,
        const SqlGeneratorOptions &options)
{
    if (!table.pk_fields().size())
        throw BadSQLOperation(_T("cannot build update statement: no key in table"));
    SqlGeneratorContext ctx;
    String sql_query = _T("UPDATE ") + table.name() + _T(" SET ");
    TypeCodes type_codes;
    type_codes.reserve(table.size());
    ParamNums param_nums;
    size_t i;
    for (i = 0; i < table.size(); ++i) {
        const Column &col = table[i];
        if (!col.is_pk() && !col.is_ro()) {
            if (!type_codes.empty())
                sql_query += _T(", ");
            sql_query += col.name() + _T(" = ");
            ++ctx.counter_;
            if (options.numbered_params_)
                sql_query += _T(":") + to_string(ctx.counter_);
            else
                sql_query += _T("?");
            param_nums[col.name()] = type_codes.size();
            type_codes.push_back(col.type());
        }
    }
    for (i = 0; i < table.pk_fields().size(); ++i) {
        const String &col_name = table.pk_fields()[i];
        param_nums[col_name] = type_codes.size();
        type_codes.push_back(table[col_name].type());
    }
    type_codes_out.swap(type_codes);
    param_nums_out.swap(param_nums);
    Key sample_key;
    table.mk_sample_key(type_codes, sample_key);
    sql_query += _T(" WHERE ")
        + KeyFilter(sample_key).generate_sql(options, &ctx);
    str_swap(sql, sql_query);
}
コード例 #9
0
ファイル: swap.c プロジェクト: nmabhinandan/fast-track-c
int main()
{
    {
      int a, b;

      a = 100;
      b = -200;

      int_swap(&a, &b);
      assert(a == -200 && b == 100);
    }

    {
      char f[] = "VLSI CAD        ";
      char s[] = "Embedded Systems";
      str_swap(f, s);
      assert(strcmp(f, "Embedded Systems") == 0);
      assert(strcmp(s, "VLSI CAD        ") == 0);
    }

    return 0;
}
コード例 #10
0
ファイル: ft_sort_params.c プロジェクト: chinspp/42
void	bubble_str_list_sort(char **array, int length)
{
	int	swapped;
	int	i;

	i = 1;
	swapped = 1;
	while (swapped)
	{
		swapped = 0;
		i = 2;
		while (i < length)
		{
			if (ft_strcmp(array[i - 1], array[i]) > 0)
			{
				str_swap(&array[i - 1], &array[i]);
				swapped = 1;
			}
			i++;
		}
		length--;
	}
}
コード例 #11
0
ファイル: engine.cpp プロジェクト: sunfirefox/yb-orm
void
EngineBase::gen_sql_insert(String &sql, TypeCodes &type_codes_out,
        ParamNums &param_nums_out, const Table &table,
        bool include_pk, bool numbered_params)
{
    int count = 1, *pcount = NULL;
    if (numbered_params)
        pcount = &count;
    String sql_query;
    sql_query = _T("INSERT INTO ") + table.name() + _T(" (");
    TypeCodes type_codes;
    type_codes.reserve(table.size());
    ParamNums param_nums;
    Strings names, pholders;
    size_t i;
    for (i = 0; i < table.size(); ++i) {
        const Column &col = table[i];
        if ((!col.is_ro() || col.is_pk()) &&
                (!col.is_pk() || include_pk))
        {
            if (pcount)
                pholders.push_back(_T(":") + to_string(count));
            else
                pholders.push_back(_T("?"));
            ++count;
            param_nums[col.name()] = type_codes.size();
            type_codes.push_back(col.type());
            names.push_back(col.name());
        }
    }
    sql_query += ExpressionList(names).get_sql() + _T(") VALUES (") + 
        ExpressionList(pholders).get_sql() + _T(")");
    str_swap(sql, sql_query);
    type_codes_out.swap(type_codes);
    param_nums_out.swap(param_nums);
}
コード例 #12
0
int dci_write(const char *path, const char *buf, size_t size, const char *fileName, struct dci_state *state)
{
	struct str_t header;
	struct str_t fileName_param;
	struct str_t fileSize_param;
	struct str_t uploadDate_param;
	struct str_t deviceID_param;
	struct str_t isFolder_param;
	struct str_t path_param;
	struct str_t data_param;
	struct str_t data;

	str_init_create(&header, "Content-Type: application/json", 0);
	str_init_create(&fileName_param, "fileName=", 0);
	str_init_create(&fileSize_param, "fileSize=", 0);
	str_init_create(&uploadDate_param, "uploadDate=", 0);
	str_init_create(&deviceID_param, "deviceID", 0);
	str_init_create(&isFolder_param, "isFolder=", 0);
	str_init_create(&path_param, "path=", 0);
	str_init_create(&data_param, "data=", 0);

	struct dc_entry_t* entry;
	entry = (struct dc_entry_t*) malloc(sizeof(struct dc_entry_t));

	memset(entry, 0, sizeof(struct dc_entry_t));

	str_init_create(&entry->fileName, fileName, 0);
	entry->fileSize = size;
	entry->uploadDate = time(0);
	str_init_create(&entry->deviceID, "binensky", 0);
	entry->isFolder = 0;
	str_init_create(&entry->path, path, 0);
	str_init_create(&entry->cache, buf, 0);
	entry->cached = 1;

	struct str_t uri;
	struct str_t param_uri;
	str_init_create(&uri, getfile_uri, 0);
	str_init(&param_uri);

	const struct str_t const* uri_parts[] =
	{
		&fileName_param,
		fileName,
		&amp,
		&fileSize_param,
		itoa(entry->fileSize),
		&amp,
		&uploadDate_param,
		itoa(entry->uploadDate),
		&amp,
		&deviceID_param,
		&entry->deviceID,
		&amp,
		&isFolder_param,
		itoa(entry->isFolder),
		&amp,
		&path_param,
		&entry->path,
		&amp,
		&data_param,
		&entry->cache
	};
	str_concat(&param_uri, sizeof(uri_parts)/sizeof(const struct str_t const*), uri_parts);
	{
		struct request_t request;
		ci_init(&request, &uri, 0, NULL, param_uri.str, POST);
		ci_request(&request);

		str_swap(&request.response.body, &entry->_id);
		ci_destroy(&request);

		struct dc_entry_t *tmp = dci_last_entry(state);
		tmp = entry;
	}
}
コード例 #13
0
static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster *m,
		bencode_item_t *output, enum call_opmode opmode, const char* addr,
		const struct sockaddr_in6 *sin)
{
	str sdp, fromtag, totag = STR_NULL, callid, viabranch;
	char *errstr;
	GQueue parsed = G_QUEUE_INIT;
	GQueue streams = G_QUEUE_INIT;
	struct call *call;
	struct call_monologue *monologue;
	int ret;
	struct sdp_ng_flags flags;
	struct sdp_chopper *chopper;

	if (!bencode_dictionary_get_str(input, "sdp", &sdp))
		return "No SDP body in message";
	if (!bencode_dictionary_get_str(input, "call-id", &callid))
		return "No call-id in message";
	if (!bencode_dictionary_get_str(input, "from-tag", &fromtag))
		return "No from-tag in message";
	bencode_dictionary_get_str(input, "to-tag", &totag);
	if (opmode == OP_ANSWER) {
		if (!totag.s)
			return "No to-tag in message";
		str_swap(&totag, &fromtag);
	}
	bencode_dictionary_get_str(input, "via-branch", &viabranch);

	if (sdp_parse(&sdp, &parsed))
		return "Failed to parse SDP";

	call_ng_process_flags(&flags, input);
	flags.opmode = opmode;

	errstr = "Incomplete SDP specification";
	if (sdp_streams(&parsed, &streams, &flags))
		goto out;

	call = call_get_opmode(&callid, m, opmode);
	errstr = "Unknown call-id";
	if (!call)
		goto out;

	if (!call->created_from && addr) {
		call->created_from = call_strdup(call, addr);
		call->created_from_addr = *sin;
	}
	/* At least the random ICE strings are contained within the call struct, so we
	 * need to hold a ref until we're done sending the reply */
	call_bencode_hold_ref(call, output);

	monologue = call_get_mono_dialogue(call, &fromtag, &totag, viabranch.s ? &viabranch : NULL);
	errstr = "Invalid dialogue association";
	if (!monologue) {
		rwlock_unlock_w(&call->master_lock);
		obj_put(call);
		goto out;
	}

	if (opmode == OP_OFFER) {
		monologue->tagtype = FROM_TAG;
	} else {
		monologue->tagtype = TO_TAG;
	}

	chopper = sdp_chopper_new(&sdp);
	bencode_buffer_destroy_add(output->buffer, (free_func_t) sdp_chopper_destroy, chopper);
	ret = monologue_offer_answer(monologue, &streams, &flags);
	if (!ret)
		ret = sdp_replace(chopper, &parsed, monologue->active_dialogue, &flags);

	rwlock_unlock_w(&call->master_lock);
	if (m->conf.redis_write) {
		redis_update(call, m->conf.redis_write, ANY_REDIS_ROLE);
	} else if (m->conf.redis) {
		redis_update(call, m->conf.redis, MASTER_REDIS_ROLE);
	}
	obj_put(call);

	gettimeofday(&(monologue->started), NULL);

	errstr = "Error rewriting SDP";
	if (ret)
		goto out;

	bencode_dictionary_add_iovec(output, "sdp", &g_array_index(chopper->iov, struct iovec, 0),
		chopper->iov_num, chopper->str_len);
	bencode_dictionary_add_string(output, "result", "ok");

	errstr = NULL;
out:
	sdp_free(&parsed);
	streams_free(&streams);

	return errstr;
}
コード例 #14
0
ファイル: sdp_neg.c プロジェクト: avble/natClientEx
/* Update single local media description to after receiving answer
 * from remote.
 */
static pj_status_t process_m_answer( pj_pool_t *pool,
				     pjmedia_sdp_media *offer,
				     pjmedia_sdp_media *answer,
				     pj_bool_t allow_asym)
{
    unsigned i;

    /* Check that the media type match our offer. */

    if (pj_strcmp(&answer->desc.media, &offer->desc.media)!=0) {
	/* The media type in the answer is different than the offer! */
	return PJMEDIA_SDPNEG_EINVANSMEDIA;
    }


    /* Check that transport in the answer match our offer. */

    /* At this point, transport type must be compatible, 
     * the transport instance will do more validation later.
     */
    if (pjmedia_sdp_transport_cmp(&answer->desc.transport, 
				  &offer->desc.transport) 
	!= PJ_SUCCESS)
    {
	return PJMEDIA_SDPNEG_EINVANSTP;
    }


    /* Check if remote has rejected our offer */
    if (answer->desc.port == 0) {
	
	/* Remote has rejected our offer. 
	 * Deactivate our media too.
	 */
	pjmedia_sdp_media_deactivate(pool, offer);

	/* Don't need to proceed */
	return PJ_SUCCESS;
    }

    /* Ticket #1148: check if remote answer does not set port to zero when
     * offered with port zero. Let's just tolerate it.
     */
    if (offer->desc.port == 0) {
	/* Don't need to proceed */
	return PJ_SUCCESS;
    }

    /* Process direction attributes */
    update_media_direction(pool, answer, offer);
 
    /* If asymetric media is allowed, then just check that remote answer has 
     * codecs that are within the offer. 
     *
     * Otherwise if asymetric media is not allowed, then we will choose only
     * one codec in our initial offer to match the answer.
     */
    if (allow_asym) {
	for (i=0; i<answer->desc.fmt_count; ++i) {
	    unsigned j;
	    pj_str_t *rem_fmt = &answer->desc.fmt[i];

	    for (j=0; j<offer->desc.fmt_count; ++j) {
		if (pj_strcmp(rem_fmt, &answer->desc.fmt[j])==0)
		    break;
	    }

	    if (j != offer->desc.fmt_count) {
		/* Found at least one common codec. */
		break;
	    }
	}

	if (i == answer->desc.fmt_count) {
	    /* No common codec in the answer! */
	    return PJMEDIA_SDPNEG_EANSNOMEDIA;
	}

	PJ_TODO(CHECK_SDP_NEGOTIATION_WHEN_ASYMETRIC_MEDIA_IS_ALLOWED);

    } else {
	/* Offer format priority based on answer format index/priority */
	unsigned offer_fmt_prior[PJMEDIA_MAX_SDP_FMT];

	/* Remove all format in the offer that has no matching answer */
	for (i=0; i<offer->desc.fmt_count;) {
	    unsigned pt;
	    pj_uint32_t j;
	    pj_str_t *fmt = &offer->desc.fmt[i];
	    

	    /* Find matching answer */
	    pt = pj_strtoul(fmt);

	    if (pt < 96) {
		for (j=0; j<answer->desc.fmt_count; ++j) {
		    if (pj_strcmp(fmt, &answer->desc.fmt[j])==0)
			break;
		}
	    } else {
		/* This is dynamic payload type.
		 * For dynamic payload type, we must look the rtpmap and
		 * compare the encoding name.
		 */
		const pjmedia_sdp_attr *a;
		pjmedia_sdp_rtpmap or_;

		/* Get the rtpmap for the payload type in the offer. */
		a = pjmedia_sdp_media_find_attr2(offer, "rtpmap", fmt);
		if (!a) {
		    pj_assert(!"Bug! Offer should have been validated");
		    return PJ_EBUG;
		}
		pjmedia_sdp_attr_get_rtpmap(a, &or_);

		/* Find paylaod in answer SDP with matching 
		 * encoding name and clock rate.
		 */
		for (j=0; j<answer->desc.fmt_count; ++j) {
		    a = pjmedia_sdp_media_find_attr2(answer, "rtpmap", 
						     &answer->desc.fmt[j]);
		    if (a) {
			pjmedia_sdp_rtpmap ar;
			pjmedia_sdp_attr_get_rtpmap(a, &ar);

			/* See if encoding name, clock rate, and channel
			 * count match 
			 */
			if (!pj_stricmp(&or_.enc_name, &ar.enc_name) &&
			    or_.clock_rate == ar.clock_rate &&
			    (pj_stricmp(&or_.param, &ar.param)==0 ||
			     (ar.param.slen==1 && *ar.param.ptr=='1')))
			{
			    /* Call custom format matching callbacks */
			    if (custom_fmt_match(pool, &or_.enc_name,
						 offer, i, answer, j, 0) ==
				PJ_SUCCESS)
			    {
				/* Match! */
				break;
			    }
			}
		    }
		}
	    }

	    if (j == answer->desc.fmt_count) {
		/* This format has no matching answer.
		 * Remove it from our offer.
		 */
		pjmedia_sdp_attr *a;

		/* Remove rtpmap associated with this format */
		a = pjmedia_sdp_media_find_attr2(offer, "rtpmap", fmt);
		if (a)
		    pjmedia_sdp_media_remove_attr(offer, a);

		/* Remove fmtp associated with this format */
		a = pjmedia_sdp_media_find_attr2(offer, "fmtp", fmt);
		if (a)
		    pjmedia_sdp_media_remove_attr(offer, a);

		/* Remove this format from offer's array */
		pj_array_erase(offer->desc.fmt, sizeof(offer->desc.fmt[0]),
			       offer->desc.fmt_count, i);
		--offer->desc.fmt_count;

	    } else {
		offer_fmt_prior[i] = j;
		++i;
	    }
	}

	if (0 == offer->desc.fmt_count) {
	    /* No common codec in the answer! */
	    return PJMEDIA_SDPNEG_EANSNOMEDIA;
	}

	/* Post process:
	 * - Resort offer formats so the order match to the answer.
	 * - Remove answer formats that unmatches to the offer.
	 */
	
	/* Resort offer formats */
	for (i=0; i<offer->desc.fmt_count; ++i) {
	    unsigned j;
	    for (j=i+1; j<offer->desc.fmt_count; ++j) {
		if (offer_fmt_prior[i] > offer_fmt_prior[j]) {
		    unsigned tmp = offer_fmt_prior[i];
		    offer_fmt_prior[i] = offer_fmt_prior[j];
		    offer_fmt_prior[j] = tmp;
		    str_swap(&offer->desc.fmt[i], &offer->desc.fmt[j]);
		}
	    }
	}

	/* Remove unmatched answer formats */
	{
	    unsigned del_cnt = 0;
	    for (i=0; i<answer->desc.fmt_count;) {
		/* The offer is ordered now, also the offer_fmt_prior */
		if (i >= offer->desc.fmt_count || 
		    offer_fmt_prior[i]-del_cnt != i)
		{
		    pj_str_t *fmt = &answer->desc.fmt[i];
		    pjmedia_sdp_attr *a;

		    /* Remove rtpmap associated with this format */
		    a = pjmedia_sdp_media_find_attr2(answer, "rtpmap", fmt);
		    if (a)
			pjmedia_sdp_media_remove_attr(answer, a);

		    /* Remove fmtp associated with this format */
		    a = pjmedia_sdp_media_find_attr2(answer, "fmtp", fmt);
		    if (a)
			pjmedia_sdp_media_remove_attr(answer, a);

		    /* Remove this format from answer's array */
		    pj_array_erase(answer->desc.fmt, 
				   sizeof(answer->desc.fmt[0]),
				   answer->desc.fmt_count, i);
		    --answer->desc.fmt_count;

		    ++del_cnt;
		} else {
		    ++i;
		}
	    }
	}
    }

    /* Looks okay */
    return PJ_SUCCESS;
}
コード例 #15
0
ファイル: sdp_neg.c プロジェクト: avble/natClientEx
/* Try to match offer with answer. */
static pj_status_t match_offer(pj_pool_t *pool,
			       pj_bool_t prefer_remote_codec_order,
                               pj_bool_t answer_with_multiple_codecs,
			       const pjmedia_sdp_media *offer,
			       const pjmedia_sdp_media *preanswer,
			       const pjmedia_sdp_session *preanswer_sdp,
			       pjmedia_sdp_media **p_answer)
{
    unsigned i;
    pj_bool_t master_has_codec = 0,
	      master_has_other = 0,
	      found_matching_codec = 0,
	      found_matching_telephone_event = 0,
	      found_matching_other = 0;
    unsigned pt_answer_count = 0;
    pj_str_t pt_answer[PJMEDIA_MAX_SDP_FMT];
    pj_str_t pt_offer[PJMEDIA_MAX_SDP_FMT];
    pjmedia_sdp_media *answer;
    const pjmedia_sdp_media *master, *slave;

    /* If offer has zero port, just clone the offer */
    if (offer->desc.port == 0) {
	answer = sdp_media_clone_deactivate(pool, offer, preanswer,
					    preanswer_sdp);
	*p_answer = answer;
	return PJ_SUCCESS;
    }

    /* If the preanswer define zero port, this media is being rejected,
     * just clone the preanswer.
     */
    if (preanswer->desc.port == 0) {
	answer = pjmedia_sdp_media_clone(pool, preanswer);
	*p_answer = answer;
	return PJ_SUCCESS;
    }

    /* Set master/slave negotiator based on prefer_remote_codec_order. */
    if (prefer_remote_codec_order) {
	master = offer;
	slave  = preanswer;
    } else {
	master = preanswer;
	slave  = offer;
    }
    
    /* With the addition of telephone-event and dodgy MS RTC SDP, 
     * the answer generation algorithm looks really shitty...
     */
    for (i=0; i<master->desc.fmt_count; ++i) {
	unsigned j;
	
	if (pj_isdigit(*master->desc.fmt[i].ptr)) {
	    /* This is normal/standard payload type, where it's identified
	     * by payload number.
	     */
	    unsigned pt;

	    pt = pj_strtoul(&master->desc.fmt[i]);
	    
	    if (pt < 96) {
		/* For static payload type, it's enough to compare just
		 * the payload number.
		 */

		master_has_codec = 1;

		/* We just need to select one codec if not allowing multiple.
		 * Continue if we have selected matching codec for previous 
		 * payload.
		 */
		if (!answer_with_multiple_codecs && found_matching_codec)
		    continue;

		/* Find matching codec in local descriptor. */
		for (j=0; j<slave->desc.fmt_count; ++j) {
		    unsigned p;
		    p = pj_strtoul(&slave->desc.fmt[j]);
		    if (p == pt && pj_isdigit(*slave->desc.fmt[j].ptr)) {
			found_matching_codec = 1;
			pt_offer[pt_answer_count] = slave->desc.fmt[j];
			pt_answer[pt_answer_count++] = slave->desc.fmt[j];
			break;
		    }
		}

	    } else {
		/* This is dynamic payload type.
		 * For dynamic payload type, we must look the rtpmap and
		 * compare the encoding name.
		 */
		const pjmedia_sdp_attr *a;
		pjmedia_sdp_rtpmap or_;
		pj_bool_t is_codec;

		/* Get the rtpmap for the payload type in the master. */
		a = pjmedia_sdp_media_find_attr2(master, "rtpmap", 
						 &master->desc.fmt[i]);
		if (!a) {
		    pj_assert(!"Bug! Offer should have been validated");
		    return PJMEDIA_SDP_EMISSINGRTPMAP;
		}
		pjmedia_sdp_attr_get_rtpmap(a, &or_);

		if (!pj_stricmp2(&or_.enc_name, "telephone-event")) {
		    if (found_matching_telephone_event)
			continue;
		    is_codec = 0;
		} else {
		    master_has_codec = 1;
		    if (!answer_with_multiple_codecs && found_matching_codec)
			continue;
		    is_codec = 1;
		}
		
		/* Find paylaod in our initial SDP with matching 
		 * encoding name and clock rate.
		 */
		for (j=0; j<slave->desc.fmt_count; ++j) {
		    a = pjmedia_sdp_media_find_attr2(slave, "rtpmap", 
						     &slave->desc.fmt[j]);
		    if (a) {
			pjmedia_sdp_rtpmap lr;
			pjmedia_sdp_attr_get_rtpmap(a, &lr);

			/* See if encoding name, clock rate, and
			 * channel count  match 
			 */
			if (!pj_stricmp(&or_.enc_name, &lr.enc_name) &&
			    or_.clock_rate == lr.clock_rate &&
			    (pj_stricmp(&or_.param, &lr.param)==0 ||
			     (lr.param.slen==0 && or_.param.slen==1 && 
						 *or_.param.ptr=='1') || 
			     (or_.param.slen==0 && lr.param.slen==1 && 
						  *lr.param.ptr=='1'))) 
			{
			    /* Match! */
			    if (is_codec) {
				pjmedia_sdp_media *o_med, *a_med;
				unsigned o_fmt_idx, a_fmt_idx;

				o_med = (pjmedia_sdp_media*)offer;
				a_med = (pjmedia_sdp_media*)preanswer;
				o_fmt_idx = prefer_remote_codec_order? i:j;
				a_fmt_idx = prefer_remote_codec_order? j:i;

				/* Call custom format matching callbacks */
				if (custom_fmt_match(pool, &or_.enc_name,
						     o_med, o_fmt_idx,
						     a_med, a_fmt_idx,
						     ALLOW_MODIFY_ANSWER) !=
				    PJ_SUCCESS)
				{
				    continue;
				}
				found_matching_codec = 1;
			    } else {
				found_matching_telephone_event = 1;
			    }

			    pt_offer[pt_answer_count] = 
						prefer_remote_codec_order?
						offer->desc.fmt[i]:
						offer->desc.fmt[j];
			    pt_answer[pt_answer_count++] = 
						prefer_remote_codec_order? 
						preanswer->desc.fmt[j]:
						preanswer->desc.fmt[i];
			    break;
			}
		    }
		}
	    }

	} else {
	    /* This is a non-standard, brain damaged SDP where the payload
	     * type is non-numeric. It exists e.g. in Microsoft RTC based
	     * UA, to indicate instant messaging capability.
	     * Example:
	     *	- m=x-ms-message 5060 sip null
	     */
	    master_has_other = 1;
	    if (found_matching_other)
		continue;

	    for (j=0; j<slave->desc.fmt_count; ++j) {
		if (!pj_strcmp(&master->desc.fmt[i], &slave->desc.fmt[j])) {
		    /* Match */
		    found_matching_other = 1;
		    pt_offer[pt_answer_count] = prefer_remote_codec_order?
						offer->desc.fmt[i]:
						offer->desc.fmt[j];
		    pt_answer[pt_answer_count++] = prefer_remote_codec_order? 
						   preanswer->desc.fmt[j]:
						   preanswer->desc.fmt[i];
		    break;
		}
	    }
	}
    }

    /* See if all types of master can be matched. */
    if (master_has_codec && !found_matching_codec) {
	return PJMEDIA_SDPNEG_NOANSCODEC;
    }

    /* If this comment is removed, negotiation will fail if remote has offered
       telephone-event and local is not configured with telephone-event

    if (offer_has_telephone_event && !found_matching_telephone_event) {
	return PJMEDIA_SDPNEG_NOANSTELEVENT;
    }
    */

    if (master_has_other && !found_matching_other) {
	return PJMEDIA_SDPNEG_NOANSUNKNOWN;
    }

    /* Seems like everything is in order.
     * Build the answer by cloning from preanswer, but rearrange the payload
     * to suit the offer.
     */
    answer = pjmedia_sdp_media_clone(pool, preanswer);
    for (i=0; i<pt_answer_count; ++i) {
	unsigned j;
	for (j=i; j<answer->desc.fmt_count; ++j) {
	    if (!pj_strcmp(&answer->desc.fmt[j], &pt_answer[i]))
		break;
	}
	pj_assert(j != answer->desc.fmt_count);
	str_swap(&answer->desc.fmt[i], &answer->desc.fmt[j]);
    }
    
    /* Remove unwanted local formats. */
    for (i=pt_answer_count; i<answer->desc.fmt_count; ++i) {
	pjmedia_sdp_attr *a;

	/* Remove rtpmap for this format */
	a = pjmedia_sdp_media_find_attr2(answer, "rtpmap", 
					 &answer->desc.fmt[i]);
	if (a) {
	    pjmedia_sdp_media_remove_attr(answer, a);
	}

	/* Remove fmtp for this format */
	a = pjmedia_sdp_media_find_attr2(answer, "fmtp", 
					 &answer->desc.fmt[i]);
	if (a) {
	    pjmedia_sdp_media_remove_attr(answer, a);
	}
    }
    answer->desc.fmt_count = pt_answer_count;

#if PJMEDIA_SDP_NEG_ANSWER_SYMMETRIC_PT
    apply_answer_symmetric_pt(pool, answer, pt_answer_count,
			      pt_offer, pt_answer);
#endif

    /* Update media direction. */
    update_media_direction(pool, offer, answer);

    *p_answer = answer;
    return PJ_SUCCESS;
}
コード例 #16
0
static str *call_update_lookup_udp(char **out, struct callmaster *m, enum call_opmode opmode, const char* addr,
		const struct sockaddr_in6 *sin)
{
	struct call *c;
	struct call_monologue *monologue;
	GQueue q = G_QUEUE_INIT;
	struct stream_params sp;
	str *ret, callid, viabranch, fromtag, totag = STR_NULL;
	int i;

	str_init(&callid, out[RE_UDP_UL_CALLID]);
	str_init(&viabranch, out[RE_UDP_UL_VIABRANCH]);
	str_init(&fromtag, out[RE_UDP_UL_FROMTAG]);
	str_init(&totag, out[RE_UDP_UL_TOTAG]);
	if (opmode == OP_ANSWER)
		str_swap(&fromtag, &totag);

	c = call_get_opmode(&callid, m, opmode);
	if (!c) {
		ilog(LOG_WARNING, "["STR_FORMAT"] Got UDP LOOKUP for unknown call-id",
			STR_FMT(&callid));
		return str_sprintf("%s 0 0.0.0.0\n", out[RE_UDP_COOKIE]);
	}

	if (!c->created_from && addr) {
		c->created_from = call_strdup(c, addr);
		c->created_from_addr = *sin;
	}

	monologue = call_get_mono_dialogue(c, &fromtag, &totag, NULL);
	if (!monologue)
		goto ml_fail;

	if (opmode == OP_OFFER) {
		monologue->tagtype = FROM_TAG;
	} else {
		monologue->tagtype = TO_TAG;
	}

	if (addr_parse_udp(&sp, out))
		goto addr_fail;

	g_queue_push_tail(&q, &sp);
	i = monologue_offer_answer(monologue, &q, NULL);
	g_queue_clear(&q);

	if (i)
		goto unlock_fail;

	ret = streams_print(&monologue->active_dialogue->medias,
			sp.index, sp.index, out[RE_UDP_COOKIE], SAF_UDP);
	rwlock_unlock_w(&c->master_lock);

	if (m->conf.redis_write) {
		redis_update(c, m->conf.redis_write, ANY_REDIS_ROLE);
	} else if (m->conf.redis) {
		redis_update(c, m->conf.redis, MASTER_REDIS_ROLE);
	}

	gettimeofday(&(monologue->started), NULL);

	ilog(LOG_INFO, "Returning to SIP proxy: "STR_FORMAT"", STR_FMT(ret));
	goto out;

ml_fail:
	ilog(LOG_ERR, "Invalid dialogue association");
	goto unlock_fail;

addr_fail:
	ilog(LOG_ERR, "Failed to parse a media stream: %s/%s:%s",
			out[RE_UDP_UL_ADDR4], out[RE_UDP_UL_ADDR6], out[RE_UDP_UL_PORT]);
	goto unlock_fail;

unlock_fail:
	rwlock_unlock_w(&c->master_lock);
	ret = str_sprintf("%s E8\n", out[RE_UDP_COOKIE]);
out:
	obj_put(c);
	return ret;
}
コード例 #17
0
ファイル: sdp_neg.c プロジェクト: deveck/Deveck.TAM
/* Update single local media description to after receiving answer
 * from remote.
 */
static pj_status_t process_m_answer( pj_pool_t *pool,
				     pjmedia_sdp_media *offer,
				     pjmedia_sdp_media *answer,
				     pj_bool_t allow_asym)
{
    unsigned i;

    /* Check that the media type match our offer. */

    if (pj_strcmp(&answer->desc.media, &offer->desc.media)!=0) {
	/* The media type in the answer is different than the offer! */
	return PJMEDIA_SDPNEG_EINVANSMEDIA;
    }


    /* Check that transport in the answer match our offer. */

    /* At this point, transport type must be compatible, 
     * the transport instance will do more validation later.
     */
    if (pjmedia_sdp_transport_cmp(&answer->desc.transport, 
				  &offer->desc.transport) 
	!= PJ_SUCCESS)
    {
	return PJMEDIA_SDPNEG_EINVANSTP;
    }


    /* Check if remote has rejected our offer */
    
    if (answer->desc.port == 0) {
	
	/* Remote has rejected our offer. 
	 * Set our port to zero too in active SDP.
	 */
	offer->desc.port = 0;
    }


    /* Process direction attributes */
    update_media_direction(pool, answer, offer);
 
    /* If asymetric media is allowed, then just check that remote answer has 
     * codecs that are within the offer. 
     *
     * Otherwise if asymetric media is not allowed, then we will choose only
     * one codec in our initial offer to match the answer.
     */
    if (allow_asym) {
	for (i=0; i<answer->desc.fmt_count; ++i) {
	    unsigned j;
	    pj_str_t *rem_fmt = &answer->desc.fmt[i];

	    for (j=0; j<offer->desc.fmt_count; ++j) {
		if (pj_strcmp(rem_fmt, &answer->desc.fmt[j])==0)
		    break;
	    }

	    if (j != offer->desc.fmt_count) {
		/* Found at least one common codec. */
		break;
	    }
	}

	if (i == answer->desc.fmt_count) {
	    /* No common codec in the answer! */
	    return PJMEDIA_SDPNEG_EANSNOMEDIA;
	}

	PJ_TODO(CHECK_SDP_NEGOTIATION_WHEN_ASYMETRIC_MEDIA_IS_ALLOWED);

    } else {
	/* Remove all format in the offer that has no matching answer */
	for (i=0; i<offer->desc.fmt_count;) {
	    unsigned pt;
	    pj_uint32_t j;
	    pj_str_t *fmt = &offer->desc.fmt[i];
	    

	    /* Find matching answer */
	    pt = pj_strtoul(fmt);

	    if (pt < 96) {
		for (j=0; j<answer->desc.fmt_count; ++j) {
		    if (pj_strcmp(fmt, &answer->desc.fmt[j])==0)
			break;
		}
	    } else {
		/* This is dynamic payload type.
		 * For dynamic payload type, we must look the rtpmap and
		 * compare the encoding name.
		 */
		const pjmedia_sdp_attr *a;
		pjmedia_sdp_rtpmap or_;

		/* Get the rtpmap for the payload type in the offer. */
		a = pjmedia_sdp_media_find_attr2(offer, "rtpmap", fmt);
		if (!a) {
		    pj_assert(!"Bug! Offer should have been validated");
		    return PJ_EBUG;
		}
		pjmedia_sdp_attr_get_rtpmap(a, &or_);

		/* Find paylaod in answer SDP with matching 
		 * encoding name and clock rate.
		 */
		for (j=0; j<answer->desc.fmt_count; ++j) {
		    a = pjmedia_sdp_media_find_attr2(answer, "rtpmap", 
						     &answer->desc.fmt[j]);
		    if (a) {
			pjmedia_sdp_rtpmap ar;
			pjmedia_sdp_attr_get_rtpmap(a, &ar);

			/* See if encoding name, clock rate, and channel
			 * count match 
			 */
			if (!pj_stricmp(&or_.enc_name, &ar.enc_name) &&
			    or_.clock_rate == ar.clock_rate &&
			    (pj_stricmp(&or_.param, &ar.param)==0 ||
			     (ar.param.slen==1 && *ar.param.ptr=='1')))
			{
			    /* Further check for G7221, negotiate bitrate. */
			    if (pj_strcmp2(&or_.enc_name, "G7221") == 0) {
				if (match_g7221(offer, i, answer, j))
				    break;
			    } else {
				/* Match! */
				break;
			    }
			}
		    }
		}
	    }

	    if (j == answer->desc.fmt_count) {
		/* This format has no matching answer.
		 * Remove it from our offer.
		 */
		pjmedia_sdp_attr *a;

		/* Remove rtpmap associated with this format */
		a = pjmedia_sdp_media_find_attr2(offer, "rtpmap", fmt);
		if (a)
		    pjmedia_sdp_media_remove_attr(offer, a);

		/* Remove fmtp associated with this format */
		a = pjmedia_sdp_media_find_attr2(offer, "fmtp", fmt);
		if (a)
		    pjmedia_sdp_media_remove_attr(offer, a);

		/* Remove this format from offer's array */
		pj_array_erase(offer->desc.fmt, sizeof(offer->desc.fmt[0]),
			       offer->desc.fmt_count, i);
		--offer->desc.fmt_count;

	    } else {
		++i;
	    }
	}

	/* Arrange format in the offer so the order match the priority
	 * in the answer
	 */
	for (i=0; i<answer->desc.fmt_count; ++i) {
	    unsigned j;
	    pj_str_t *fmt = &answer->desc.fmt[i];

	    for (j=i; j<offer->desc.fmt_count; ++j) {
		if (pj_strcmp(fmt, &offer->desc.fmt[j])==0) {
		    str_swap(&offer->desc.fmt[i], &offer->desc.fmt[j]);
		    break;
		}
	    }
	}
    }

    /* Looks okay */
    return PJ_SUCCESS;
}
コード例 #18
0
ファイル: sdp_neg.c プロジェクト: deveck/Deveck.TAM
/* Try to match offer with answer. */
static pj_status_t match_offer(pj_pool_t *pool,
			       const pjmedia_sdp_media *offer,
			       const pjmedia_sdp_media *preanswer,
			       const pjmedia_sdp_media *orig_local,
			       pjmedia_sdp_media **p_answer)
{
    unsigned i;
    pj_bool_t offer_has_codec = 0,
	      offer_has_telephone_event = 0,
	      offer_has_other = 0,
	      found_matching_codec = 0,
	      found_matching_telephone_event = 0,
	      found_matching_other = 0;
    unsigned pt_answer_count = 0;
    pj_str_t pt_answer[PJMEDIA_MAX_SDP_FMT];
    pjmedia_sdp_media *answer;

    /* With the addition of telephone-event and dodgy MS RTC SDP, 
     * the answer generation algorithm looks really shitty...
     */
    for (i=0; i<offer->desc.fmt_count; ++i) {
	unsigned j;
	
	if (pj_isdigit(*offer->desc.fmt[i].ptr)) {
	    /* This is normal/standard payload type, where it's identified
	     * by payload number.
	     */
	    unsigned pt;

	    pt = pj_strtoul(&offer->desc.fmt[i]);
	    
	    if (pt < 96) {
		/* For static payload type, it's enough to compare just
		 * the payload number.
		 */

		offer_has_codec = 1;

		/* We just need to select one codec. 
		 * Continue if we have selected matching codec for previous 
		 * payload.
		 */
		if (found_matching_codec)
		    continue;

		/* Find matching codec in local descriptor. */
		for (j=0; j<preanswer->desc.fmt_count; ++j) {
		    unsigned p;
		    p = pj_strtoul(&preanswer->desc.fmt[j]);
		    if (p == pt && pj_isdigit(*preanswer->desc.fmt[j].ptr)) {
			found_matching_codec = 1;
			pt_answer[pt_answer_count++] = preanswer->desc.fmt[j];
			break;
		    }
		}

	    } else {
		/* This is dynamic payload type.
		 * For dynamic payload type, we must look the rtpmap and
		 * compare the encoding name.
		 */
		const pjmedia_sdp_attr *a;
		pjmedia_sdp_rtpmap or_;
		pj_bool_t is_codec;

		/* Get the rtpmap for the payload type in the offer. */
		a = pjmedia_sdp_media_find_attr2(offer, "rtpmap", 
						 &offer->desc.fmt[i]);
		if (!a) {
		    pj_assert(!"Bug! Offer should have been validated");
		    return PJMEDIA_SDP_EMISSINGRTPMAP;
		}
		pjmedia_sdp_attr_get_rtpmap(a, &or_);

		if (!pj_strcmp2(&or_.enc_name, "telephone-event")) {
		    offer_has_telephone_event = 1;
		    if (found_matching_telephone_event)
			continue;
		    is_codec = 0;
		} else {
		    offer_has_codec = 1;
		    if (found_matching_codec)
			continue;
		    is_codec = 1;
		}
		
		/* Find paylaod in our initial SDP with matching 
		 * encoding name and clock rate.
		 */
		for (j=0; j<preanswer->desc.fmt_count; ++j) {
		    a = pjmedia_sdp_media_find_attr2(preanswer, "rtpmap", 
						     &preanswer->desc.fmt[j]);
		    if (a) {
			pjmedia_sdp_rtpmap lr;
			pjmedia_sdp_attr_get_rtpmap(a, &lr);

			/* See if encoding name, clock rate, and
			 * channel count  match 
			 */
			if (!pj_stricmp(&or_.enc_name, &lr.enc_name) &&
			    or_.clock_rate == lr.clock_rate &&
			    (pj_strcmp(&or_.param, &lr.param)==0 ||
			     (or_.param.slen==1 && *or_.param.ptr=='1'))) 
			{
			    /* Match! */
			    if (is_codec) {
				/* Further check for G7221, negotiate bitrate. */
				if (pj_strcmp2(&or_.enc_name, "G7221")  == 0 &&
				    match_g7221(offer, i, preanswer, j) == 0)
				{
				    continue;
				}
				found_matching_codec = 1;
			    } else {
				found_matching_telephone_event = 1;
			    }

			    pt_answer[pt_answer_count++] = preanswer->desc.fmt[j];
			    break;
			}
		    }
		}
	    }

	} else {
	    /* This is a non-standard, brain damaged SDP where the payload
	     * type is non-numeric. It exists e.g. in Microsoft RTC based
	     * UA, to indicate instant messaging capability.
	     * Example:
	     *	- m=x-ms-message 5060 sip null
	     */
	    offer_has_other = 1;
	    if (found_matching_other)
		continue;

	    for (j=0; j<preanswer->desc.fmt_count; ++j) {
		if (!pj_strcmp(&offer->desc.fmt[i], &preanswer->desc.fmt[j])) {
		    /* Match */
		    found_matching_other = 1;
		    pt_answer[pt_answer_count++] = preanswer->desc.fmt[j];
		    break;
		}
	    }
	}
    }

    /* See if all types of offer can be matched. */
    if (offer_has_codec && !found_matching_codec) {
	return PJMEDIA_SDPNEG_NOANSCODEC;
    }

    /* If this comment is removed, negotiation will fail if remote has offered
       telephone-event and local is not configured with telephone-event

    if (offer_has_telephone_event && !found_matching_telephone_event) {
	return PJMEDIA_SDPNEG_NOANSTELEVENT;
    }
    */

    if (offer_has_other && !found_matching_other) {
	return PJMEDIA_SDPNEG_NOANSUNKNOWN;
    }

    /* Seems like everything is in order.
     * Build the answer by cloning from local media, but rearrange the payload
     * to suit the offer.
     */
    answer = pjmedia_sdp_media_clone(pool, orig_local);
    for (i=0; i<pt_answer_count; ++i) {
	unsigned j;
	for (j=i; j<answer->desc.fmt_count; ++j) {
	    if (!pj_strcmp(&answer->desc.fmt[j], &pt_answer[i]))
		break;
	}
	pj_assert(j != answer->desc.fmt_count);
	str_swap(&answer->desc.fmt[i], &answer->desc.fmt[j]);
    }
    
    /* Remove unwanted local formats. */
    for (i=pt_answer_count; i<answer->desc.fmt_count; ++i) {
	pjmedia_sdp_attr *a;

	/* Remove rtpmap for this format */
	a = pjmedia_sdp_media_find_attr2(answer, "rtpmap", 
					 &answer->desc.fmt[i]);
	if (a) {
	    pjmedia_sdp_media_remove_attr(answer, a);
	}

	/* Remove fmtp for this format */
	a = pjmedia_sdp_media_find_attr2(answer, "fmtp", 
					 &answer->desc.fmt[i]);
	if (a) {
	    pjmedia_sdp_media_remove_attr(answer, a);
	}
    }
    answer->desc.fmt_count = pt_answer_count;

    /* If offer has zero port, set our answer with zero port too */
    if (offer->desc.port==0)
	answer->desc.port = 0;

    /* Update media direction. */
    update_media_direction(pool, offer, answer);

    *p_answer = answer;
    return PJ_SUCCESS;
}
コード例 #19
0
ファイル: test.c プロジェクト: Jing0/neolibc
int main(int argc, char const *argv[]) {
    /* str_new */
    str_t string = str_new();
    /* str_set */
    str_set(string, "   %d%d%d", 1, 2, 3);
    /* str_append */
    str_append(string, "appending   end");
    /* str_println */
    str_println(string);
    /* str_reverse */
    str_reverse(string);
    str_println(string);
    /* str_length */
    printf("size before trimming:\t%zu\n", str_length(string));
    /* str_trim */
    str_trim(string);
    printf("size after trimming:\t%zu\n", str_length(string));
    /* str_substr */
    str_t substr = str_substr(string, 0, 3);
    printf("substr before swap:\t");
    str_println(substr);
    printf("string before swap:\t");
    str_println(string);
    str_swap(substr, string);
    printf("substr after swap:\t");
    str_println(substr);
    printf("string after swap:\t");
    str_println(string);
    printf("is string empty?\t%s\n",
           str_isempty(string) ? "Yes" : "No");
    printf("is substr equal to string?\t%s\n",
           str_compare(substr, string) ? "No" : "Yes");

    /* str_readFromFile */
    str_readFromFile(string, "neostring.c");
    printf("string size: %zu\t", str_length(string));
    printf("string capacity: %zu\n", string->capacity);
    str_set(string, "ok");
    printf("Before trimToSize():\n");
    printf("string size: %zu\t", str_length(string));
    printf("string capacity: %zu\n", string->capacity);
    /* str_trimToSize */
    str_trimToSize(string);
    printf("After trimToSize():\n");
    printf("string size: %zu\t", str_length(string));
    printf("string capacity: %zu\n", string->capacity);
    str_set(string, "hello, world");
    str_println(string);
    printf("%zu\n", string->size);
    printf("string has prefix ello?\t%s\n", str_hasPrefix(string, "ello") ? "Yes" : "No");
    printf("%zu\n", string->size);
    printf("string has suffix orld?\t%s\n", str_hasSuffix(string, "orld") ? "Yes" : "No");
    /* str_clone */
    str_t clone = str_clone(string);
    /* str_toupper */
    str_toupper(clone);
    /* str_writeToFile */
    str_writeToFile(clone, "./test.txt");
    /* str_destroy */
    str_destroy(string);
    str_destroy(clone);
    str_destroy(substr);
    return 0;
}