示例#1
0
文件: hmp.c 项目: btb/d2x
void hmp2mid(char *hmp_name, unsigned char **midbuf, unsigned int *midlen)
{
	int mi, i;
	short ms, time_div = 0xC0;
	hmp_file *hmp=NULL;

	hmp = hmp_open(hmp_name);
	if (hmp == NULL)
		return;

	*midlen = 0;
	time_div = hmp->tempo*1.6;

	// write MIDI-header
	*midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 4);
	memcpy(&(*midbuf)[*midlen], "MThd", 4);
	*midlen += 4;
	mi = MIDIINT(6);
	*midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + sizeof(mi));
	memcpy(&(*midbuf)[*midlen], &mi, sizeof(mi));
	*midlen += sizeof(mi);
	ms = MIDISHORT(1);
	*midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + sizeof(ms));
	memcpy(&(*midbuf)[*midlen], &ms, sizeof(ms));
	*midlen += sizeof(ms);
	ms = MIDISHORT(hmp->num_trks);
	*midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + sizeof(ms));
	memcpy(&(*midbuf)[*midlen], &ms, sizeof(ms));
	*midlen += sizeof(ms);
	ms = MIDISHORT(time_div);
	*midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + sizeof(ms));
	memcpy(&(*midbuf)[*midlen], &ms, sizeof(ms));
	*midlen += sizeof(ms);
	*midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + sizeof(tempo));
	memcpy(&(*midbuf)[*midlen], &tempo, sizeof(tempo));
	*midlen += sizeof(tempo);

	// tracks
	for (i = 1; i < hmp->num_trks; i++)
	{
		int midtrklenpos = 0;

		*midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 4);
		memcpy(&(*midbuf)[*midlen], "MTrk", 4);
		*midlen += 4;
		midtrklenpos = *midlen;
		mi = 0;
		*midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + sizeof(mi));
		*midlen += sizeof(mi);
		mi = hmptrk2mid(hmp->trks[i].data, hmp->trks[i].len, midbuf, midlen);
		mi = MIDIINT(mi);
		memcpy(&(*midbuf)[midtrklenpos], &mi, 4);
	}

	hmp_close(hmp);
}
示例#2
0
d_define_method(emitter, embed_parameter)(struct s_object *self, const char *id, void *parameter) {
    struct s_signal *signal;
    void **new_parameters;
    if ((signal = d_call(self, m_emitter_get, id))) {
        signal->parameters_size++;
        if ((new_parameters = (void **) d_realloc(signal->parameters, (signal->parameters_size*sizeof(void *))))) {
            signal->parameters = new_parameters;
            signal->parameters[signal->parameters_size-1] = parameter;
        }
    }
    return (void *)signal;
}
示例#3
0
文件: gr.c 项目: CDarrow/DXX-Retro
int gr_set_mode(u_int32_t mode)
{
	unsigned int w, h;
	char *gr_bm_data;

	if (mode<=0)
		return 0;

	w=SM_W(mode);
	h=SM_H(mode);

	if (!gr_check_mode(mode))
	{
		con_printf(CON_URGENT,"Cannot set %ix%i. Fallback to 640x480\n",w,h);
		w=640;
		h=480;
		Game_screen_mode=mode=SM(w,h);
	}

	gr_bm_data=(char *)grd_curscreen->sc_canvas.cv_bitmap.bm_data;//since we use realloc, we want to keep this pointer around.
	memset( grd_curscreen, 0, sizeof(grs_screen));
	grd_curscreen->sc_mode = mode;
	grd_curscreen->sc_w = w;
	grd_curscreen->sc_h = h;
	grd_curscreen->sc_aspect = fixdiv(grd_curscreen->sc_w*GameCfg.AspectX,grd_curscreen->sc_h*GameCfg.AspectY);
	gr_init_canvas(&grd_curscreen->sc_canvas, d_realloc(gr_bm_data,w*h), BM_OGL, w, h);
	gr_set_current_canvas(NULL);

	ogl_init_window(w,h);//platform specific code
	ogl_get_verinfo();
	OGL_VIEWPORT(0,0,w,h);
	ogl_init_state();
	gamefont_choose_game_font(w,h);
	gr_remap_color_fonts();
	gr_remap_mono_fonts();

	return 0;
}
示例#4
0
d_define_method(label, set_content_char)(struct s_object *self, char *string_content, TTF_Font *font, struct s_object *environment) {
    d_using(label);
    size_t string_length = f_string_strlen(string_content);
    if (string_length > 0) {
        if (label_attributes->string_content) {
            /* realloc only if really needed */
            if (label_attributes->size < (string_length+1)) {
                if ((label_attributes->string_content = (char *)d_realloc(label_attributes->string_content, (string_length+1))))
                    label_attributes->size = (string_length+1);
                else
                    d_die(d_error_malloc);
            }
        } else if ((label_attributes->string_content = (char *)d_malloc(string_length+1)))
            label_attributes->size = (string_length+1);
        else
            d_die(d_error_malloc);
        strncpy(label_attributes->string_content, string_content, string_length);
        label_attributes->string_content[string_length] = '\0';
    } else if (label_attributes->string_content)
        memset(label_attributes->string_content, '\0', label_attributes->size);
    p_label_update_texture(self, font, environment);
    return self;
}
示例#5
0
d_define_method(stream, read_string)(struct s_object *self, struct s_object *string_supplied, size_t size) {
	d_using(stream);
	struct s_string_attributes *string_attributes = NULL;
	char character, buffer[d_stream_block_size];
	size_t readed_local = 0;
	int tail = d_true;
	if ((stream_attributes->flags&e_stream_flag_opened) == e_stream_flag_opened) {
		if (((stream_attributes->parameters&O_RDWR) == O_RDWR) || ((stream_attributes->parameters&O_RDONLY) == O_RDONLY)) {
			while ((readed_local < size) && (read(stream_attributes->descriptor, &character, 1) > 0)) {
				tail = d_false;
				if ((character != '\n') && (character != '\0'))
					buffer[readed_local++] = character;
				else
					break;
			}
			if (!tail) {
				buffer[readed_local] = '\0';
				if (!string_supplied) {
					string_supplied = f_string_new_size(d_new(string), buffer, (readed_local + 1));
				} else {
					string_attributes = d_cast(string_supplied, string);
					if (string_attributes->size < (readed_local + 1)) {
						string_attributes->content = d_realloc(string_attributes->content, (readed_local + 1));
						string_attributes->length = (readed_local + 1);
					}
					strncpy(string_attributes->content, buffer, readed_local);
					string_attributes->content[readed_local] = '\0';
					string_attributes->length = readed_local;
				}
			} else
				string_supplied = NULL;
		} else
			d_throw(v_exception_unsupported, "read in a write-only stream exception");
	} else
		d_throw(v_exception_closed, "read in a closed stream exception");
	return string_supplied;
}
示例#6
0
// Set up everything for our music
// NOTE: you might think this is done once per runtime but it's not! It's done for EACH song so that each mission can have it's own descent.sng structure. We COULD optimize that by only doing this once per mission.
void songs_init()
{
    int i = 0;
    char inputline[80+1];
    PHYSFS_file * fp = NULL;
    char sng_file[PATH_MAX];

    Songs_initialized = 0;

    if (BIMSongs != NULL)
        d_free(BIMSongs);

    memset(sng_file, '\0', sizeof(sng_file));
    if (Current_mission != NULL) // try MISSION_NAME.sngdxx - might be rarely used but handy if you want a songfile for a specific mission outside of the mission hog file. use special extension to not crash with other ports of the game
    {
        snprintf(sng_file, strlen(Current_mission_filename)+8, "%s.sngdxx", Current_mission_filename);
        fp = PHYSFSX_openReadBuffered(sng_file);
    }

    if (fp == NULL) // try descent.sngdxx - a songfile specifically for dxx which level authors CAN use (dxx does not care if descent.sng contains MP3/OGG/etc. as well) besides the normal descent.sng containing files other versions of the game cannot play. this way a mission can contain a DOS-Descent compatible OST (hmp files) as well as a OST using MP3, OGG, etc.
        fp = PHYSFSX_openReadBuffered( "descent.sngdxx" );

    if (fp == NULL) // try to open regular descent.sng
        fp = PHYSFSX_openReadBuffered( "descent.sng" );

    if ( fp == NULL ) // No descent.sng available. Define a default song-set
    {
        int predef=30; // define 30 songs - period

        MALLOC(BIMSongs, bim_song_info, predef);
        if (!BIMSongs)
            return;

        strncpy(BIMSongs[SONG_TITLE].filename, "descent.hmp",sizeof(BIMSongs[SONG_TITLE].filename));
        strncpy(BIMSongs[SONG_BRIEFING].filename, "briefing.hmp",sizeof(BIMSongs[SONG_BRIEFING].filename));
        strncpy(BIMSongs[SONG_CREDITS].filename, "credits.hmp",sizeof(BIMSongs[SONG_CREDITS].filename));
        strncpy(BIMSongs[SONG_ENDLEVEL].filename, "endlevel.hmp",sizeof(BIMSongs[SONG_ENDLEVEL].filename));	// can't find it? give a warning
        strncpy(BIMSongs[SONG_ENDGAME].filename, "endgame.hmp",sizeof(BIMSongs[SONG_ENDGAME].filename));	// ditto

        for (i = SONG_FIRST_LEVEL_SONG; i < predef; i++) {
            snprintf(BIMSongs[i].filename, sizeof(BIMSongs[i].filename), "game%02d.hmp", i - SONG_FIRST_LEVEL_SONG + 1);
            if (!PHYSFSX_exists(BIMSongs[i].filename,1))
                snprintf(BIMSongs[i].filename, sizeof(BIMSongs[i].filename), "game%d.hmp", i - SONG_FIRST_LEVEL_SONG);
            if (!PHYSFSX_exists(BIMSongs[i].filename,1))
            {
                memset(BIMSongs[i].filename, '\0', sizeof(BIMSongs[i].filename)); // music not available
                break;
            }
        }
    }
    else
    {
        while (!PHYSFS_eof(fp))
        {
            PHYSFSX_fgets(inputline, 80, fp );
            if ( strlen( inputline ) )
            {
                BIMSongs = d_realloc(BIMSongs, sizeof(bim_song_info)*(i+1));
                memset(BIMSongs[i].filename, '\0', sizeof(BIMSongs[i].filename));
                sscanf( inputline, "%15s", BIMSongs[i].filename );

                if (strrchr(BIMSongs[i].filename, '.'))
                    if (!stricmp(strrchr(BIMSongs[i].filename, '.'), ".hmp") ||
                            !stricmp(strrchr(BIMSongs[i].filename, '.'), ".mp3") ||
                            !stricmp(strrchr(BIMSongs[i].filename, '.'), ".ogg") ||
                            !stricmp(strrchr(BIMSongs[i].filename, '.'), ".aif") ||
                            !stricmp(strrchr(BIMSongs[i].filename, '.'), ".mid") ||
                            !stricmp(strrchr(BIMSongs[i].filename, '.'), ".flac")
                       )
                        i++;
            }
        }

        // HACK: If Descent.hog is patched from 1.0 to 1.5, descent.sng is turncated. So let's patch it up here
        if (i==12 && PHYSFSX_fsize("descent.sng")==422)
        {
            BIMSongs = d_realloc(BIMSongs, sizeof(bim_song_info)*(i+15));
            for (i = 12; i <= 26; i++)
                snprintf(BIMSongs[i].filename, sizeof(BIMSongs[i].filename), "game%02d.hmp", i-4);
        }
    }

    Num_bim_songs = i;
    Songs_initialized = 1;
    if (fp != NULL)
        PHYSFS_close(fp);

    if (GameArg.SndNoMusic)
        GameCfg.MusicType = MUSIC_TYPE_NONE;

    // If SDL_Mixer is not supported (or deactivated), switch to no-music type if SDL_mixer-related music type was selected
#ifdef USE_SDLMIXER
    if (GameArg.SndDisableSdlMixer)
#else
    if (1)
#endif
    {
#ifndef _WIN32
        if (GameCfg.MusicType == MUSIC_TYPE_BUILTIN)
            GameCfg.MusicType = MUSIC_TYPE_NONE;
#endif
        if (GameCfg.MusicType == MUSIC_TYPE_CUSTOM)
            GameCfg.MusicType = MUSIC_TYPE_NONE;
    }

    if (GameCfg.MusicType == MUSIC_TYPE_REDBOOK)
        RBAInit();
#ifdef USE_SDLMIXER
    else if (GameCfg.MusicType == MUSIC_TYPE_CUSTOM)
        jukebox_load();
#endif

    songs_set_volume(GameCfg.MusicVolume);
}
示例#7
0
int mix_play_file(char *filename, int loop, void (*hook_finished_track)())
{
	SDL_RWops *rw = NULL;
	PHYSFS_file *filehandle = NULL;
	char full_path[PATH_MAX];
	char *fptr;
	unsigned int bufsize = 0;

	mix_free_music();	// stop and free what we're already playing, if anything

	fptr = strrchr(filename, '.');

	if (fptr == NULL)
		return 0;

	// It's a .hmp!
	if (!d_stricmp(fptr, ".hmp"))
	{
		hmp2mid(filename, &current_music_hndlbuf, &bufsize);
		rw = SDL_RWFromConstMem(current_music_hndlbuf,bufsize*sizeof(char));
		current_music = Mix_LoadMUS_RW(rw);
	}

	// try loading music via given filename
	if (!current_music)
		current_music = Mix_LoadMUS(filename);

	// allow the shell convention tilde character to mean the user's home folder
	// chiefly used for default jukebox level song music referenced in 'descent.m3u' for Mac OS X
	if (!current_music && *filename == '~')
	{
		snprintf(full_path, PATH_MAX, "%s%s", PHYSFS_getUserDir(),
				 &filename[1 + (!strncmp(&filename[1], PHYSFS_getDirSeparator(), strlen(PHYSFS_getDirSeparator())) ? 
				 strlen(PHYSFS_getDirSeparator()) : 0)]);
		current_music = Mix_LoadMUS(full_path);
		if (current_music)
			filename = full_path;	// used later for possible error reporting
	}
		

	// no luck. so it might be in Searchpath. So try to build absolute path
	if (!current_music)
	{
		PHYSFSX_getRealPath(filename, full_path);
		current_music = Mix_LoadMUS(full_path);
		if (current_music)
			filename = full_path;	// used later for possible error reporting
	}

	// still nothin'? Let's open via PhysFS in case it's located inside an archive
	if (!current_music)
	{
		filehandle = PHYSFS_openRead(filename);
		if (filehandle != NULL)
		{
			current_music_hndlbuf = d_realloc(current_music_hndlbuf, sizeof(char *)*PHYSFS_fileLength(filehandle));
			bufsize = PHYSFS_read(filehandle, current_music_hndlbuf, sizeof(char), PHYSFS_fileLength(filehandle));
			rw = SDL_RWFromConstMem(current_music_hndlbuf,bufsize*sizeof(char));
			PHYSFS_close(filehandle);
			current_music = Mix_LoadMUS_RW(rw);
		}
	}

	if (current_music)
	{
		Mix_PlayMusic(current_music, (loop ? -1 : 1));
		Mix_HookMusicFinished(hook_finished_track ? hook_finished_track : mix_free_music);
		return 1;
	}
	else
	{
		con_printf(CON_CRITICAL,"Music %s could not be loaded: %s\n", filename, Mix_GetError());
		mix_stop_music();
	}

	return 0;
}
示例#8
0
void play_hmi (void * arg)
{
	int i;
	int pos = 0x308;
	int n_chunks = 0;
	int low_dtime;
	int low_chunk;
	int csec, lcsec;
	int qid;
	int ipc_read = 0;
	int k=0;
	
	struct msgbuf *rcv;
	
	Track_info *t_info;

	con_printf(CON_DEBUG,"play_hmi\n");
	
	stop = 0;
	ipc_read=0;

	rcv=d_malloc(sizeof(long) + 16);
	
	rcv->mtype=1;
	rcv->mtext[0]='0';

	qid=msgget ((key_t) ('l'<<24) | ('d'<<16) | ('e'<<8) | 's', 0660);
	if(qid == -1)
	{	
		return;
	}
	
	do
	{
		ipc_read=do_ipc(qid,rcv,0);
	}
	while(rcv->mtext[0] != 'p');
	
	stop=0;
	rcv->mtext[0] = '0';
	
	seq_init();
	
	n_chunks=data[0x30];
	
	t_info = d_malloc(sizeof(Track_info)*n_chunks);
	
	while(1)
	{
		
		for(i=0;i<n_chunks;i++)
		{
			t_info[i].position = pos + 12;
			t_info[i].status = PLAYING;
			t_info[i].time = get_dtime(data,&t_info[i].position);
			pos += (( (0xff & data[pos + 5]) << 8 ) + (0xff & data[pos + 4]));
		}

		lcsec = 0;

		SEQ_START_TIMER();
		do
		{
			low_chunk = -1;
			k++;
			i=0;
			do
			{
				if (t_info[i].status == PLAYING)
					low_chunk = i;
				i++;
			}
			while((low_chunk <=0) && (i<n_chunks));
			
			if (low_chunk == -1)
			  break;
			
			low_dtime = t_info[low_chunk].time;
			
			for(i=1;i<n_chunks;i++)
			{
				if ((t_info[i].time < low_dtime) && 
					(t_info[i].status == PLAYING))
				{
					low_dtime = t_info[i].time;
					low_chunk = i;
				}
			}
			
			if (low_dtime < 0)
				con_printf(CON_URGENT,"Serious warning: d_time negative!!!!!!\n");
			
			csec = 0.86 * low_dtime;
			
			//flush sequencer buffer after 20 events
			if (k == 20)
			{
				ioctl(seqfd, SNDCTL_SEQ_SYNC);
				k = 0;
			}
#ifdef WANT_AWE32
			cut_trough();
#endif
			if (csec != lcsec) {
				SEQ_WAIT_TIME(csec);
			}
			
			lcsec = csec;
			
			t_info[low_chunk].status = do_track_event(data,&t_info[low_chunk].position);
			
			if (t_info[low_chunk].status == 3)
			{
				con_printf(CON_URGENT,"Error playing data in chunk %d\n",low_chunk);
				t_info[low_chunk].status = STOPPED;
			}
			
			if (t_info[low_chunk].status == PLAYING)
			  t_info[low_chunk].time += get_dtime(data,&t_info[low_chunk].position);
			
			//Check if the song has reached the end
			stop = t_info[0].status;
			for(i=1;i<n_chunks;i++)
				stop &= t_info[i].status;

// ZICO - since we don't seem to have a real repeat call we need a hack
// endlevel song does change rephmi to 0 while endlevel. endlevel song takes about 1950 csec till it's finished
			if (!rephmi && csec > 1950)
				send_ipc("s");
			
			if((do_ipc(qid,rcv,IPC_NOWAIT) > 0) && (rcv->mtext[0]=='p'))
			{
				n_chunks=data[0x30];
				t_info = d_realloc(t_info,sizeof(Track_info)*n_chunks);
				stop = 1;
				rcv->mtext[0] = '0';  
				stop_all();
			}
		}
		while(!stop);
		SEQ_STOP_TIMER();
		if( stop == 2)
		{
			stop_all();
			do
			{
				ipc_read=do_ipc(qid,rcv,0);
			}
			while(rcv->mtext[0] != 'p');
			rcv->mtext[0] = '0';
			n_chunks=data[0x30];
			t_info = d_realloc(t_info,sizeof(Track_info)*n_chunks);
			stop = 0;
		}
		pos=0x308;
	}
	d_free(data);
	d_free(t_info);
	d_free(rcv);
	
}
示例#9
0
int do_ipc(int qid, struct msgbuf *buf, int flags)
{
	int ipc_read;
	CFILE *fptr = NULL;
	float last_volume = volume;
	int l=0;
	
	ipc_read = msgrcv(qid,buf,16,0,flags | MSG_NOERROR);
	
	switch (ipc_read)
	{
	 case -1:
		if (errno == ENOMSG)
		  break;
		perror("IPC trouble");
		break;
	 case 0:
		break;
	 default:
		con_printf(CON_DEBUG,"do_ipc %s\n", buf->mtext);//##########3
		switch (buf->mtext[0])
		{
		case 'v':
			volume = (double)(atof(buf->mtext + 1) / 128.0);
			con_printf(CON_DEBUG,"vol %f->%f\n", last_volume, volume);
			if (last_volume <= 0 && volume > 0)
			{
				buf->mtext[0] = 'p'; // start playing again if volume raised above 0
				strcpy(buf->mtext + 1, digi_last_midi_song);
				// fall through to case 'p'
			}
			else if (last_volume > 0 && volume <= 0)
			{
				strcpy(buf->mtext, "s"); // stop playing if volume reduced to 0
				stop = 2;
				break;
			}
			else
				break;
		case 'p':
			if (buf->mtext[1])
			{
				strcpy(digi_last_midi_song, buf->mtext + 1);
				if (volume > 0)
					fptr = cfopen((buf->mtext + 1), "rb");
			}
			if(fptr != NULL)
			{
				l = cfilelength(fptr);
				data=d_realloc(data,(size_t) l);
				cfread(data, l, 1, fptr);
				cfclose(fptr);
				con_printf(CON_DEBUG, "good. fpr=%p l=%i data=%p\n", fptr, l, data);//##########3
				stop = 0;
			}
			else
			{
				strcpy(buf->mtext, "s"); // not playing, thus "stop".
				stop = 2;
			}
			break;
		 case 's':
			stop = 2;
			break;
		 case 'q':
			break;
		}
	}

	return ipc_read;
}
示例#10
0
文件: hmp.c 项目: btb/d2x
static unsigned int hmptrk2mid(ubyte* data, int size, unsigned char **midbuf, unsigned int *midlen)
{
	ubyte *dptr = data;
	ubyte lc1 = 0,last_com = 0;
	uint d;
	int n1, n2;
	unsigned int offset = *midlen;

	while (data < dptr + size)
	{
		if (data[0] & 0x80) {
			ubyte b = (data[0] & 0x7F);
			*midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 1);
			memcpy(&(*midbuf)[*midlen], &b, 1);
			*midlen += 1;
		}
		else {
			d = (data[0] & 0x7F);
			n1 = 0;
			while ((data[n1] & 0x80) == 0) {
				n1++;
				d += (data[n1] & 0x7F) << (n1 * 7);
				}
			n1 = 1;
			while ((data[n1] & 0x80) == 0) {
				n1++;
				if (n1 == 4)
					return 0;
				}
			for(n2 = 0; n2 <= n1; n2++) {
				ubyte b = (data[n1 - n2] & 0x7F);

				if (n2 != n1)
					b |= 0x80;
				*midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 1);
				memcpy(&(*midbuf)[*midlen], &b, 1);
				*midlen += 1;
				}
			data += n1;
		}
		data++;
		if (*data == 0xFF) { //meta?
			*midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 3 + data[2]);
			memcpy(&(*midbuf)[*midlen], data, 3 + data[2]);
			*midlen += 3 + data[2];
			if (data[1] == 0x2F)
				break;
		}
		else {
			lc1=data[0] ;
			if ((lc1&0x80) == 0)
				return 0;
			switch (lc1 & 0xF0) {
				case 0x80:
				case 0x90:
				case 0xA0:
				case 0xB0:
				case 0xE0:
					if (lc1 != last_com)
					{
						*midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 1);
						memcpy(&(*midbuf)[*midlen], &lc1, 1);
						*midlen += 1;
					}
					*midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 2);
					memcpy(&(*midbuf)[*midlen], data + 1, 2);
					*midlen += 2;
					data += 3;
					break;
				case 0xC0:
				case 0xD0:
					if (lc1 != last_com)
					{
						*midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 1);
						memcpy(&(*midbuf)[*midlen], &lc1, 1);
						*midlen += 1;
					}
					*midbuf = (unsigned char *) d_realloc(*midbuf, *midlen + 1);
					memcpy(&(*midbuf)[*midlen], data + 1, 1);
					*midlen += 1;
					data += 2;
					break;
				default:
					return 0;
				}
			last_com = lc1;
		}
	}
	return (*midlen - offset);
}