コード例 #1
0
ファイル: fix_message.c プロジェクト: weixu8/libtrading
/*
 * The function assumes that the following patterns have fixed sizes:
 * - "BeginString=" ("8=") is 2 bytes long
 * - "CheckSum=" ("10=") is 3 bytes long
 * - "MsgType=" ("35=") is 3 bytes long
 */
static bool checksum(struct fix_message *self, struct buffer *buffer)
{
	const char *start;
	int offset;

	start = buffer_start(buffer);

	/* The number of bytes between tag MsgType and buffer's start */
	offset = start - (self->msg_type - 3);

	/*
	 * Checksum tag and its trailing delimiter increase
	 * the message's length by seven bytes - "10=***\x01"
	 */
	if (buffer_size(buffer) + offset < self->body_length + 7)
		return false;

	/* Buffer's start will point to the CheckSum tag */
	buffer_advance(buffer, self->body_length - offset);

	self->check_sum = parse_field(buffer, CheckSum);
	if (!self->check_sum)
		return false;

	if (!verify_checksum(self, buffer))
		return false;

	/* Go back to analyze other fields */
	buffer_advance(buffer, start - buffer_start(buffer));

	return true;
}
コード例 #2
0
ファイル: fix_message.c プロジェクト: weixu8/libtrading
int fix_message_parse(struct fix_message *self, struct buffer *buffer)
{
	unsigned long size;
	const char *start;

	self->head_buf = buffer;

retry:
	start	= buffer_start(buffer);
	size	= buffer_size(buffer);

	if (!size)
		goto fail;

	if (!first_three_fields(self))
		goto fail;

	if (!checksum(self, buffer))
		goto fail;

	rest_of_message(self, buffer);

	return 0;

fail:
	if (size > FIX_MAX_MESSAGE_SIZE)
		goto retry;

	buffer_advance(buffer, start - buffer_start(buffer));

	return -1;
}
コード例 #3
0
ファイル: fix_message.c プロジェクト: bjoto/libtrading
int fix_message_parse(struct fix_message *self, struct buffer *buffer)
{
	int ret = FIX_MSG_STATE_PARTIAL;
	unsigned long size;
	const char *start;

	self->head_buf = buffer;

retry:
	start	= buffer_start(buffer);
	size	= buffer_size(buffer);

	if (!size)
		goto fail;

	ret = first_three_fields(self);
	if (ret)
		goto fail;

	ret = checksum(self, buffer);
	if (ret)
		goto fail;

	rest_of_message(self, buffer);

	return 0;

fail:
	if (ret != FIX_MSG_STATE_PARTIAL)
		goto retry;

	buffer_advance(buffer, start - buffer_start(buffer));

	return -1;
}
コード例 #4
0
reckless::detail::thread_input_buffer::thread_input_buffer(std::size_t size) :
    input_consumed_flag(false),
    size_(size),
    pinput_start_(buffer_start()),
    pinput_end_(buffer_start())
{
}
コード例 #5
0
char* reckless::detail::thread_input_buffer::wraparound()
{
#ifndef NDEBUG
    auto p = pinput_start_.load(std::memory_order_relaxed);
    auto marker = *reinterpret_cast<formatter_dispatch_function_t**>(p);
    assert(WRAPAROUND_MARKER == marker);
#endif
    pinput_start_.store(buffer_start(), std::memory_order_relaxed);
    return buffer_start();
}
コード例 #6
0
// Moves an input-buffer pointer forward by the given distance while
// maintaining the invariant that:
//
// * p is aligned by FRAME_ALIGNMENT
// * p never points at the end of the buffer; it always wraps around to the
//   beginning of the circular buffer.
//
// The distance must never be so great that the pointer moves *past* the end of
// the buffer. To do so would be an error in our context, since no input frame
// is allowed to be discontinuous.
char* reckless::detail::thread_input_buffer::advance_frame_pointer(char* p, std::size_t distance)
{
    assert(is_aligned(p));
    assert(is_aligned(distance));
    p += distance;
    assert(size_ >= static_cast<std::size_t>(p - buffer_start()));
    auto remaining = size_ - (p - buffer_start());
    if(remaining == 0)
        p = buffer_start();
    return p;
}
コード例 #7
0
ファイル: cog.c プロジェクト: agsimeonov/jitd
//Scans the full the Cog and returns iterator.
iterator scan_full_array( struct cog *cog) {
  if( cog->type == COG_BTREE )
    {
      struct cog *a = cog->data.btree.lhs;
      struct cog *b = cog->data.btree.rhs;
      return iter_concat(
      scan_full_array(a),
      scan_full_array(b)
    );      
    }
  if( cog->type == COG_CONCAT )
    {
      struct cog *a = cog->data.concat.lhs;
      struct cog *b = cog->data.concat.rhs;
      return iter_concat(
      scan_full_array(a),
      scan_full_array(b)
    );
    }
  if( cog->type == COG_SORTEDARRAY )
    {
      int start = cog->data.array.start;
      int len = cog->data.array.len;
      struct record *in = buffer_start(cog->data.array.records, start);
      struct buffer *out = buffer_alloc(cog->data.sortedarray.len + 1);
      int i, tgt;
      iterator ret;
      for(i = 0, tgt = 0; i < len; i++){
        record_copy(&(in[i]), &(out->data[tgt]));
        tgt++;
      }
      ret = array_iter_alloc(out, 0, tgt);
      return ret;
    }
  if( cog->type == COG_ARRAY )
    {
      int start = cog->data.array.start;
      int len = cog->data.array.len;
      struct record *in = buffer_start(cog->data.array.records, start);
      struct buffer *out = buffer_alloc(cog->data.array.len );
      int i, tgt;
      iterator ret;
      for(i = 0, tgt = 0; i < len; i++){
        record_copy(&(in[i]), &(out->data[tgt]));
        tgt++;
      }
      ret = array_iter_alloc(out, 0, tgt);
      return ret;
    }
    fprintf(stderr, "Invalid Cog Type %d\n", cog->type);
    exit(-1);
}
コード例 #8
0
struct itch50_message *itch50_message_decode(struct buffer *buf)
{
	size_t available;
	size_t size;
	void *start;
	u8 type;

	available = buffer_size(buf);

	if (!available)
		return NULL;

	type = buffer_peek_8(buf);

	size = itch50_message_size(type);
	if (!size)
		return NULL;

	if (available < size)
		return NULL;

	start = buffer_start(buf);

	buffer_advance(buf, size);

	return start;
}
コード例 #9
0
int itch40_message_decode(struct buffer *buf, struct itch40_message *msg)
{
	size_t available;
	size_t size;
	u8 type;

	available = buffer_size(buf);

	if (!available)
		return -1;

	type = buffer_peek_8(buf);

	size = itch40_message_size(type);
	if (!size)
		return -1;

	if (available < size)
		return -1;

	memcpy(msg, buffer_start(buf), size);

	buffer_advance(buf, size);

	return 0;
}
コード例 #10
0
ファイル: boe_message.c プロジェクト: JerJohn15/libtrading
int boe_message_decode(struct buffer *buf, struct boe_message *msg, size_t size)
{
	u16 magic, len;
	void *start;
	size_t count;

	start = buffer_start(buf);

	magic = buffer_get_le16(buf);
	if (magic != BOE_MAGIC)
		return -1;

	len = buffer_get_le16(buf);

	count = BOE_MAGIC_LEN + len;

	if (count > size)
		count = size;

	memcpy(msg, start, count);

	buffer_advance(buf, len - BOE_MSG_LENGTH_LEN);

	return 0;
}
コード例 #11
0
ファイル: control_generic.c プロジェクト: 5py/libmpg123
static void generic_load(mpg123_handle *fr, char *arg, int state)
{
	if(param.usebuffer)
	{
		buffer_resync();
		if(mode == MODE_PAUSED && state != MODE_PAUSED) buffer_start();
	}
	if(mode != MODE_STOPPED)
	{
		close_track();
		mode = MODE_STOPPED;
	}
	if(!open_track(arg))
	{
		generic_sendmsg("E Error opening stream: %s", arg);
		generic_sendmsg("P 0");
		return;
	}
	mpg123_seek(fr, 0, SEEK_SET); /* This finds ID3v2 at beginning. */
	if(mpg123_meta_check(fr) & MPG123_NEW_ID3)
	{
		generic_sendinfoid3(fr);
		mpg123_meta_free(fr);
	}
	else generic_sendinfo(arg);

	if(htd.icy_name.fill) generic_sendmsg("I ICY-NAME: %s", htd.icy_name.p);
	if(htd.icy_url.fill)  generic_sendmsg("I ICY-URL: %s", htd.icy_url.p);

	mode = state;
	init = 1;
	generic_sendmsg(mode == MODE_PAUSED ? "P 1" : "P 2");
}
コード例 #12
0
ファイル: buffer.c プロジェクト: JerJohn15/libtrading
ssize_t buffer_xwrite(struct buffer *buf, int fd)
{
	size_t count;
	void *start;

	start	= buffer_start(buf);
	count	= buffer_size(buf);

	return xwrite(fd, start, count);
}
コード例 #13
0
int fix_message_parse(struct fix_message *self, struct fix_dialect *dialect, struct buffer *buffer, unsigned long flags)
{
    const char *start;
    int ret;

    self->head_buf = buffer;

    TRACE(LIBTRADING_FIX_MESSAGE_PARSE(self, dialect, buffer));
retry:
    ret = FIX_MSG_STATE_PARTIAL;

    start	= buffer_start(buffer);

    if (!buffer_size(buffer))
        goto fail;

    ret = first_three_fields(self, flags);
    if (ret)
        goto fail;

    ret = checksum(self, buffer, flags);
    if (ret)
        goto fail;

    rest_of_message(self, dialect, buffer);

    self->iov[0].iov_base	= (void *)start;
    self->iov[0].iov_len 	= buffer_start(buffer) - start;

    TRACE(LIBTRADING_FIX_MESSAGE_PARSE_RET());

    return 0;

fail:
    if (ret != FIX_MSG_STATE_PARTIAL)
        goto retry;

    buffer_advance(buffer, start - buffer_start(buffer));

    TRACE(LIBTRADING_FIX_MESSAGE_PARSE_ERR());

    return -1;
}
コード例 #14
0
/*
 * The function assumes that the following patterns have fixed sizes:
 * - "BeginString=" ("8=") is 2 bytes long
 * - "CheckSum=" ("10=") is 3 bytes long
 * - "MsgType=" ("35=") is 3 bytes long
 */
static int checksum(struct fix_message *self, struct buffer *buffer, unsigned long flags)
{
    const char *start;
    int offset;
    int ret;

    start = buffer_start(buffer);

    /* The number of bytes between tag MsgType and buffer's start */
    offset = start - (self->msg_type - 3);

    /*
     * Checksum tag and its trailing delimiter increase
     * the message's length by seven bytes - "10=***\x01"
     */
    if (buffer_size(buffer) + offset < self->body_length + 7) {
        ret = FIX_MSG_STATE_PARTIAL;
        goto exit;
    }

    if (flags & FIX_PARSE_FLAG_NO_CSUM) {
        ret = 0;
        goto exit;
    }

    /* Buffer's start will point to the CheckSum tag */
    buffer_advance(buffer, self->body_length - offset);

    ret = match_field(buffer, CheckSum, &self->check_sum);
    if (ret)
        goto exit;

    if (!verify_checksum(self, buffer)) {
        ret = FIX_MSG_STATE_GARBLED;
        goto exit;
    }

    /* Go back to analyze other fields */
    buffer_advance(buffer, start - buffer_start(buffer));

exit:
    return ret;
}
コード例 #15
0
ファイル: buffer.c プロジェクト: weixu8/libtrading
char *buffer_find(struct buffer *buf, char c)
{
	while (buffer_first_char(buf) != c) {
		if (!buffer_size(buf))
			return NULL;

		buffer_advance(buf, 1);
	}

	return buffer_start(buf);
}
コード例 #16
0
ファイル: buffer.c プロジェクト: JerJohn15/libtrading
void buffer_compact(struct buffer *buf)
{
	size_t count;
	void *start;

	start	= buffer_start(buf);
	count	= buffer_size(buf);

	memmove(buf->data, start, count);

	buf->start	= 0;
	buf->end	= count;
}
コード例 #17
0
ファイル: buffer.c プロジェクト: akisaarinen/libtrading
char *buffer_find(struct buffer *buf, u8 c)
{
	while (true) {
		if (!buffer_size(buf))
			return NULL;

		if (buffer_peek_8(buf) == c)
			break;

		buffer_advance(buf, 1);
	}

	return buffer_start(buf);
}
コード例 #18
0
ファイル: G2ConHelper.c プロジェクト: kaffeemonster/g2cd
bool do_read(struct epoll_event *p_entry, some_fd epoll_fd GCC_ATTR_UNUSED_PARAM)
{
	g2_connection_t *w_entry = (g2_connection_t *)p_entry->data.ptr;
	ssize_t result = 0;
	bool ret_val = true;
#ifdef DEBUG_DEVEL
	if(!w_entry->recv) {
		logg_posd(LOGF_DEBUG, "%s Ip: %p#I\tFDNum: %i\n",
		          "no recv buffer!", &w_entry->remote_host, w_entry->com_socket);
		w_entry->flags.dismissed = true;
		return false;
	}
#endif

	do	{
		set_s_errno(0);
		result = my_epoll_recv(epoll_fd, w_entry->com_socket, buffer_start(*w_entry->recv),
		              buffer_remaining(*w_entry->recv), 0);
	} while(-1 == result && EINTR == s_errno);

	switch(result)
	{
	default:
		w_entry->recv->pos += result;
		break;
	case  0:
		if(buffer_remaining(*w_entry->recv))
		{
			if(EAGAIN != s_errno) {
				logg_posd(LOGF_DEVEL_OLD, "%s ERRNO=%i Ip: %p#I\tFDNum: %i\n",
				          "EOF reached!", s_errno, &w_entry->remote_host, w_entry->com_socket);
				w_entry->flags.dismissed = true;
				ret_val = false;
			} else
				logg_devel("Nothing to read!\n");
		}
		break;
	case -1:
		if(!(EAGAIN == s_errno || EWOULDBLOCK == s_errno)) {
			logg_serrno(LOGF_DEBUG, "write");
			w_entry->flags.dismissed = true;
			ret_val = false;
		}
		break;
	}
	logg_develd_old("ret_val: %i\tpos: %u\tlim: %u\n", ret_val, w_entry->recv->pos, w_entry->recv->limit);
	
	return ret_val;
}
コード例 #19
0
ファイル: soupbin3_session.c プロジェクト: Hegen/libtrading
static int soupbin3_packet_decode(struct buffer *buf, uint16_t len, struct soupbin3_packet *packet)
{
	size_t size;
	void *start;

	start = buffer_start(buf);

	size = sizeof(uint16_t) + len;

	memcpy(packet, start - sizeof(uint16_t), size);

	buffer_advance(buf, len);

	return 0;
}
コード例 #20
0
ファイル: fix_message.c プロジェクト: bjoto/libtrading
static int parse_value(struct buffer *self, const char **value)
{
	char *start, *end;

	start = buffer_start(self);

	end = buffer_find(self, 0x01);

	if (!end || *end != 0x01)
		return FIX_MSG_STATE_PARTIAL;

	buffer_advance(self, 1);

	*value = start;

	return 0;
}
コード例 #21
0
ファイル: fix_message.c プロジェクト: weixu8/libtrading
static const char *parse_value(struct buffer *self)
{
	char *start, *end;

	start = buffer_start(self);

	end = buffer_find(self, 0x01);

	if (!end)
		return NULL;

	if (*end != 0x01)
		return NULL;

	buffer_advance(self, 1);

	return start;
}
コード例 #22
0
static int parse_tag(struct buffer *self, int *tag)
{
    const char *delim;
    const char *start;
    const char *end;
    int ret;

    start = buffer_start(self);
    delim = buffer_find(self, '=');

    if (!delim || *delim != '=')
        return FIX_MSG_STATE_PARTIAL;
    ret = fix_uatoi(start, &end);
    if (end != delim)
        return FIX_MSG_STATE_GARBLED;

    buffer_advance(self, 1);

    *tag = ret;

    return 0;
}
コード例 #23
0
ファイル: fix_message.c プロジェクト: weixu8/libtrading
static int parse_tag(struct buffer *self)
{
	const char *delim;
	const char *start;
	char *end;
	int ret;

	start = buffer_start(self);
	delim = buffer_find(self, '=');

	if (!delim)
		return 0;

	if (*delim != '=')
		return 0;

	ret = strtol(start, &end, 10);
	if (end != delim)
		return 0;

	buffer_advance(self, 1);

	return ret;
}
コード例 #24
0
ファイル: builtin-check.c プロジェクト: JerJohn15/libtrading
int cmd_check(int argc, char *argv[])
{
	struct buffer *comp_buf, *uncomp_buf;
	z_stream stream;
	struct stat st;
	int fd;

	setlocale(LC_ALL, "");

	if (argc < 2)
		usage();

	parse_args(argc, argv);

	init_stream(&stream);

	fd = open(filename, O_RDONLY);
	if (fd < 0)
		die("%s: %s: %s\n", program, filename, strerror(errno));

	if (fstat(fd, &st) < 0)
		die("%s: %s: %s\n", program, filename, strerror(errno));

	comp_buf = buffer_mmap(fd, st.st_size);
	if (!comp_buf)
		die("%s: %s\n", program, strerror(errno));

	stream.next_in = (void *) buffer_start(comp_buf);

	uncomp_buf = buffer_new(BUFFER_SIZE);
	if (!uncomp_buf)
		die("%s: %s\n", program, strerror(errno));

	for (;;) {
		struct itch41_message *msg;

retry_size:
		if (buffer_size(uncomp_buf) < sizeof(u16)) {
			ssize_t nr;

			buffer_compact(uncomp_buf);

			nr = buffer_inflate(comp_buf, uncomp_buf, &stream);
			if (nr < 0)
				die("%s: zlib error\n", program);

			if (!nr)
				break;

			if (show_progress)
				print_progress(comp_buf, st.st_size);

			goto retry_size;
		}

		buffer_advance(uncomp_buf, sizeof(u16));

retry_message:
		msg = itch41_message_decode(uncomp_buf);
		if (!msg) {
			ssize_t nr;

			buffer_compact(uncomp_buf);

			nr = buffer_inflate(comp_buf, uncomp_buf, &stream);
			if (nr < 0)
				die("%s: zlib error\n", program);

			if (!nr)
				break;

			if (show_progress)
				print_progress(comp_buf, st.st_size);

			goto retry_message;
		}

		if (verbose)
			printf("%c", msg->MessageType);

		stats[msg->MessageType - 'A']++;
	}

	printf("\n");

	buffer_munmap(comp_buf);

	buffer_delete(uncomp_buf);

	if (close(fd) < 0)
		die("%s: %s: %s\n", program, filename, strerror(errno));

	release_stream(&stream);

	print_stats();

	return 0;
}
コード例 #25
0
char* reckless::detail::thread_input_buffer::allocate_input_frame(std::size_t size)
{
    // Conceptually, we have the invariant that
    //   pinput_start_ <= pinput_end_,
    // and the memory area after pinput_end is free for us to use for
    // allocating a frame. However, the fact that it's a circular buffer means
    // that:
    // 
    // * The area after pinput_end is actually non-contiguous, wraps around
    //   at the end of the buffer and ends at pinput_start.
    //   
    // * Except, when pinput_end itself has fallen over the right edge and we
    //   have the case pinput_end <= pinput_start. Then the *used* memory is
    //   non-contiguous, and the free memory is contiguous (it still starts at
    //   pinput_end and ends at pinput_start modulo circular buffer size).
    //   
    // (This is easier to understand by drawing it on a paper than by reading
    // the comment text).
    auto mask = frame_alignment_mask();
    size = (size + mask) & ~mask;

    // We can't write a frame that is larger than the entire capacity of the
    // input buffer. If you hit this assert then you either need to write a
    // smaller log entry, or you need to make the input buffer larger.
    assert(size < size_);
 
    while(true) {
        auto pinput_end = pinput_end_;
        // FIXME these asserts should / can be enabled again?
        assert(static_cast<std::size_t>(pinput_end - buffer_start()) < size_);
        assert(is_aligned(pinput_end));

        // Even if we get an "old" value for pinput_start_ here, that's OK
        // because other threads will never cause the amount of available
        // buffer space to shrink. So either there is enough buffer space and
        // we're done, or there isn't and we'll wait for an input-consumption
        // event which creates a full memory barrier and hence gives us an
        // updated value for pinput_start_. So memory_order_relaxed should be
        // fine here.
        auto pinput_start = pinput_start_.load(std::memory_order_relaxed);
        std::ptrdiff_t free = pinput_start - pinput_end;
        if(free > 0) {
            // Free space is contiguous.
            // Technically, there is enough room if size == free. But the
            // problem with using the free space in this situation is that when
            // we increase pinput_end_ by size, we end up with pinput_start_ ==
            // pinput_end_. Now, given that state, how do we know if the buffer
            // is completely filled or empty? So, it's easier to just check for
            // size < free instead of size <= free, and pretend we're out
            // of space if size == free. Same situation applies in the else
            // clause below.
            if(likely(static_cast<std::ptrdiff_t>(size) < free)) {
                pinput_end_ = advance_frame_pointer(pinput_end, size);
                return pinput_end;
            } else {
                // Not enough room. Wait for the output thread to consume some
                // input.
                wait_input_consumed();
            }
        } else {
            // Free space is non-contiguous.
            // TODO should we use an end pointer instead of a size_?
            std::size_t free1 = size_ - (pinput_end - buffer_start());
            if(likely(size < free1)) {
                // There's enough room in the first segment.
                pinput_end_ = advance_frame_pointer(pinput_end, size);
                return pinput_end;
            } else {
                std::size_t free2 = pinput_start - buffer_start();
                if(likely(size < free2)) {
                    // We don't have enough room for a continuous input frame
                    // in the first segment (at the end of the circular
                    // buffer), but there is enough room in the second segment
                    // (at the beginning of the buffer). To instruct the output
                    // thread to skip ahead to the second segment, we need to
                    // put a marker value at the current position. We're
                    // supposed to be guaranteed enough room for the wraparound
                    // marker because frame alignment is at least the size of
                    // the marker.
                    *reinterpret_cast<formatter_dispatch_function_t**>(pinput_end_) =
                        WRAPAROUND_MARKER;
                    pinput_end_ = advance_frame_pointer(buffer_start(), size);
                    return buffer_start();
                } else {
                    // Not enough room. Wait for the output thread to consume
                    // some input.
                    wait_input_consumed();
                }
            }
        }
    }
}
コード例 #26
0
ファイル: log_facility.c プロジェクト: kaffeemonster/g2cd
static int logg_internal(const enum loglevel level,
                         const char *file,
                         const char *func,
                         const unsigned int line,
                         int log_errno,
                         const char *fmt,
                         va_list args
                        )
{
	struct big_buff *logg_buff;
	int ret_val, old_errno, retry_cnt;

	old_errno  = errno;

	/* get our tls-print buf */
	if(!(logg_buff = logg_get_buf()))
	{
		/*
		 * hmmm, something went wrong, lets see, if we can get the message to
		 * the user by other means
		 */
		return do_vlogging(level, fmt, args);
	}

	/* add time, if wanted, to buffer */
	if(server.settings.logging.add_date_time)
		logg_buff->pos += add_time_to_buffer(buffer_start(*logg_buff), buffer_remaining(*logg_buff));

	/* put out the "extra" stuff, if there */
	if(file)
	{
		retry_cnt = 0;
		prefetch(strlpcpy);
		prefetch(file);
		prefetch(func);
		/*
		 * calling snprintf for 2 * strcpy + an itoa is "nice"
		 * but goes round the full stdio bloat:
		 * snprintf->vsnprintf->vfprintf-> myriads of funcs to print
		 */
		do
		{
			char *sptr, *stmp, *rstart;
			size_t remaining;

			stmp = sptr = buffer_start(*logg_buff);
			remaining = buffer_remaining(*logg_buff);
			rstart = strlpcpy(sptr, file, remaining);
			remaining -= rstart - sptr;
			if(unlikely(remaining < 7))
				goto realloc;
			sptr = rstart;

			*sptr++ = ':';
			remaining--;
			rstart = strlpcpy(sptr, func, remaining);
			remaining -= rstart - sptr;
			if(unlikely(remaining < 18)) /* make sure we have enough space */
				goto realloc;
			sptr = rstart;

			*sptr++ = '(';
			*sptr++ = ')';
			*sptr++ = '@';
			remaining -= 3;
			rstart = put_dec_trunc(sptr, line); /* 99,999 lines should be... */
			strreverse(sptr, rstart - 1);
			remaining -= rstart - sptr;
			if(unlikely(remaining < 2))
				goto realloc;
			sptr = rstart;
			*sptr++ = ':';
			*sptr++ = ' ';
			logg_buff->pos += sptr - stmp;
			break;
realloc:
			/* now we are in a slow path, no need to hurry */
			{
				struct big_buff *tmp_buff;
				size_t len = strlen(file) + strlen(func) + 6 + 30 + strlen(fmt) * 3;
				len = ROUND_ALIGN(len * 2, 2048) + logg_buff->capacity;
				tmp_buff = realloc(logg_buff, sizeof(*logg_buff) + len);
				if(tmp_buff) {
					logg_buff = tmp_buff;
					logg_buff->limit = logg_buff->capacity = len;
				} else
					break;
				retry_cnt++;
			}
		} while(retry_cnt < 4);
	}

	ret_val = 0; retry_cnt = 0;
	/* format the message in tls */
	do
	{
		size_t len = logg_buff->capacity;
		va_list tmp_valist;
		if(ret_val < 0)
		{
			len *= 2;
			if(++retry_cnt > 4) {
				ret_val = 0;
				break;
			}
		}
		else if((size_t)ret_val > buffer_remaining(*logg_buff))
			len = ROUND_ALIGN((size_t)ret_val * 2, 1024); /* align to a k */
		if(unlikely(len != logg_buff->capacity))
		{
			struct big_buff *tmp_buf = realloc(logg_buff, sizeof(*logg_buff) + len);
			if(tmp_buf) {
				logg_buff = tmp_buf;
				logg_buff->limit = logg_buff->capacity = len;
			} else {
				ret_val = buffer_remaining(*logg_buff);
				break;
			}
		}
		/* put msg printed out in buffer */
		va_copy(tmp_valist, args);
		ret_val = my_vsnprintf(buffer_start(*logg_buff), buffer_remaining(*logg_buff), fmt, tmp_valist);
		va_end(tmp_valist);
		/* error? repeat */
	} while(unlikely(ret_val < 0 || (size_t)ret_val > buffer_remaining(*logg_buff)));
	logg_buff->pos += (size_t)ret_val;

	/* add errno string if wanted */
	if(log_errno)
	{
		if(buffer_remaining(*logg_buff) < STRERROR_R_SIZE + 4)
		{
			size_t len = logg_buff->capacity * 2;
			struct big_buff *tmp_buff = realloc(logg_buff, sizeof(*logg_buff) + len);
			if(!tmp_buff)
				goto no_errno;
			logg_buff = tmp_buff;
			logg_buff->limit = logg_buff->capacity += len;
		}
		*buffer_start(*logg_buff) = ':'; logg_buff->pos++;
		*buffer_start(*logg_buff) = ' '; logg_buff->pos++;
		{
#if defined STRERROR_R_CHAR_P || defined HAVE_MTSAFE_STRERROR || WIN32 || !(defined HAVE_STRERROR_R || HAVE_DECL_STRERROR_R-0 > 0)
			size_t err_str_len;
# ifdef WIN32
			const char *s = buffer_start(*logg_buff);
			if(!(err_str_len = FormatMessage(
				FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, /* flags */
				0, /* pointer to other source */
				old_errno, /* msg id */
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* language */
				buffer_start(*logg_buff), /* buffer */
				buffer_remaining(*logg_buff)-1, /* size */
				0 /* va_args */
			))) {
				s = "Unknown system error";
				err_str_len = strlen(s) < buffer_remaining(*logg_buff)-2 ?
				              strlen(s) : buffer_remaining(*logg_buff)-2;
			}
# else
#  ifdef STRERROR_R_CHAR_P
			/*
			 * the f***ing GNU-Version of strerror_r wich returns
			 * a char * to the buffer....
			 * This sucks especially in conjunction with strnlen,
			 * wich needs a #define __GNU_SOURCE, but conflicts
			 * with this...
			 */
			const char *s = strerror_r(old_errno, buffer_start(*logg_buff), buffer_remaining(*logg_buff)-2);
#  else
			/*
			 * Ol Solaris seems to have a static msgtable, so
			 * strerror is threadsafe and we don't have a
			 * _r version
			 */
			/*
			 * we also simply fall into here if strerror is not thread
			 * safe, but we have nothing else.
			 * Since what should we do in this case... _sys_errlist
			 * is a bsd extentions.
			 */
			const char *s = strerror(old_errno);
#  endif
			if(s)
				err_str_len = strnlen(s, buffer_remaining(*logg_buff)-2);
			else {
				s = "Unknown system error";
				err_str_len = strlen(s) < (buffer_remaining(*logg_buff)-2) ?
				              strlen(s) : buffer_remaining(*logg_buff)-2;
			}
# endif

			if(s != buffer_start(*logg_buff))
				my_memcpy(buffer_start(*logg_buff), s, err_str_len);
			logg_buff->pos += err_str_len;
#else
			if(!strerror_r(old_errno, buffer_start(*logg_buff), buffer_remaining(*logg_buff)))
//			if(!strerror_s(buffer_start(*logg_buff), buffer_remaining(*logg_buff), old_errno))
				logg_buff->pos += strnlen(buffer_start(*logg_buff), buffer_remaining(*logg_buff));
			else
			{
				size_t err_l;
				const char *bs;
				if(EINVAL == errno) {
					err_l = str_size("Unknown errno value!");
					bs = "Unknown errno value!";
				} else if(ERANGE == errno) {
					err_l = str_size("errno msg to long for buffer!");
					bs = "errno msg to long for buffer!";
				} else {
					err_l = str_size("failure while retrieving errno msg!");
					bs = "failure while retrieving errno msg!";
				}
				err_l = (buffer_remaining(*logg_buff)-2) >= err_l ? err_l : (buffer_remaining(*logg_buff)-2);
				my_memcpy(buffer_start(*logg_buff), bs, err_l);
				logg_buff->pos += err_l;
			}
#endif
		}
		*buffer_start(*logg_buff) = '\n'; logg_buff->pos++;
		*buffer_start(*logg_buff) = '\0';
	}
no_errno:

	/* output that stuff */
	buffer_flip(*logg_buff);
	ret_val = do_logging(level, buffer_start(*logg_buff), buffer_remaining(*logg_buff));
	logg_ret_buf(logg_buff);
	return ret_val;
}
コード例 #27
0
ファイル: term.c プロジェクト: BacioiuC/love-native-android
static void term_handle_input(mpg123_handle *fr, audio_output_t *ao, int do_delay)
{
  int n = 1;
  /* long offset = 0; */
  
  while(n > 0) {
    fd_set r;
    struct timeval t;
    char val;

    t.tv_sec=0;
    t.tv_usec=(do_delay) ? 10*1000 : 0;
    
    FD_ZERO(&r);
    FD_SET(0,&r);
    n = select(1,&r,NULL,NULL,&t);
    if(n > 0 && FD_ISSET(0,&r)) {
      if(read(0,&val,1) <= 0)
        break;

      switch(tolower(val)) {
	case MPG123_BACK_KEY:
        if(!param.usebuffer) ao->flush(ao);
				else buffer_resync();
		if(paused) pause_cycle=(int)(LOOP_CYCLES/mpg123_tpf(fr));

		if(mpg123_seek_frame(fr, 0, SEEK_SET) < 0)
		error1("Seek to begin failed: %s", mpg123_strerror(fr));

		framenum=0;
		break;
	case MPG123_NEXT_KEY:
		if(!param.usebuffer) ao->flush(ao);
		else buffer_resync(); /* was: plain_buffer_resync */
	  next_track();
	  break;
	case MPG123_QUIT_KEY:
		debug("QUIT");
		if(stopped)
		{
			stopped = 0;
			if(param.usebuffer)
			{
				buffer_resync();
				buffer_start();
			}
		}
		set_intflag();
		offset = 0;
	  break;
	case MPG123_PAUSE_KEY:
  	  paused=1-paused;
	  if(paused) {
			/* Not really sure if that is what is wanted
			   This jumps in audio output, but has direct reaction to pausing loop. */
			if(param.usebuffer) buffer_resync();

			pause_recycle(fr);
	  }
		if(stopped)
		{
			stopped=0;
			if(param.usebuffer) buffer_start();
		}
	  fprintf(stderr, "%s", (paused) ? MPG123_PAUSED_STRING : MPG123_EMPTY_STRING);
	  break;
	case MPG123_STOP_KEY:
	case ' ':
		/* when seeking while stopped and then resuming, I want to prevent the chirp from the past */
		if(!param.usebuffer) ao->flush(ao);
	  stopped=1-stopped;
	  if(paused) {
		  paused=0;
		  offset -= pause_cycle;
	  }
		if(param.usebuffer)
		{
			if(stopped) buffer_stop();
			else
			{
				/* When we stopped buffer for seeking, we must resync. */
				if(offset) buffer_resync();

				buffer_start();
			}
		}
	  fprintf(stderr, "%s", (stopped) ? MPG123_STOPPED_STRING : MPG123_EMPTY_STRING);
	  break;
	case MPG123_FINE_REWIND_KEY:
	  if(param.usebuffer) seekmode();
	  offset--;
	  break;
	case MPG123_FINE_FORWARD_KEY:
	  seekmode();
	  offset++;
	  break;
	case MPG123_REWIND_KEY:
	  seekmode();
  	  offset-=10;
	  break;
	case MPG123_FORWARD_KEY:
	  seekmode();
	  offset+=10;
	  break;
	case MPG123_FAST_REWIND_KEY:
	  seekmode();
	  offset-=50;
	  break;
	case MPG123_FAST_FORWARD_KEY:
	  seekmode();
	  offset+=50;
	  break;
	case MPG123_VOL_UP_KEY:
		mpg123_volume_change(fr, 0.02);
	break;
	case MPG123_VOL_DOWN_KEY:
		mpg123_volume_change(fr, -0.02);
	break;
	case MPG123_PITCH_UP_KEY:
	case MPG123_PITCH_BUP_KEY:
	case MPG123_PITCH_DOWN_KEY:
	case MPG123_PITCH_BDOWN_KEY:
	case MPG123_PITCH_ZERO_KEY:
	{
		double new_pitch = param.pitch;
		switch(val) /* Not tolower here! */
		{
			case MPG123_PITCH_UP_KEY:    new_pitch += MPG123_PITCH_VAL;  break;
			case MPG123_PITCH_BUP_KEY:   new_pitch += MPG123_PITCH_BVAL; break;
			case MPG123_PITCH_DOWN_KEY:  new_pitch -= MPG123_PITCH_VAL;  break;
			case MPG123_PITCH_BDOWN_KEY: new_pitch -= MPG123_PITCH_BVAL; break;
			case MPG123_PITCH_ZERO_KEY:  new_pitch = 0.0; break;
		}
		set_pitch(fr, ao, new_pitch);
		fprintf(stderr, "New pitch: %f\n", param.pitch);
	}
	break;
	case MPG123_VERBOSE_KEY:
		param.verbose++;
		if(param.verbose > VERBOSE_MAX)
		{
			param.verbose = 0;
			clear_stat();
		}
		mpg123_param(fr, MPG123_VERBOSE, param.verbose, 0);
	break;
	case MPG123_RVA_KEY:
		if(++param.rva > MPG123_RVA_MAX) param.rva = 0;
		mpg123_param(fr, MPG123_RVA, param.rva, 0);
		mpg123_volume_change(fr, 0.);
	break;
	case MPG123_PREV_KEY:
		if(!param.usebuffer) ao->flush(ao);
		else buffer_resync(); /* was: plain_buffer_resync */

		prev_track();
	break;
	case MPG123_PLAYLIST_KEY:
		fprintf(stderr, "%s\nPlaylist (\">\" indicates current track):\n", param.verbose ? "\n" : "");
		print_playlist(stderr, 1);
		fprintf(stderr, "\n");
	break;
	case MPG123_TAG_KEY:
		fprintf(stderr, "%s\n", param.verbose ? "\n" : "");
		print_id3_tag(fr, param.long_id3, stderr);
		fprintf(stderr, "\n");
	break;
	case MPG123_MPEG_KEY:
		if(param.verbose) print_stat(fr,0,0); /* Make sure that we are talking about the correct frame. */
		fprintf(stderr, "\n");
		print_header(fr);
		fprintf(stderr, "\n");
	break;
	case MPG123_HELP_KEY:
	{ /* This is more than the one-liner before, but it's less spaghetti. */
		int i;
		fprintf(stderr,"\n\n -= terminal control keys =-\n");
		for(i=0; i<(sizeof(term_help)/sizeof(struct keydef)); ++i)
		{
			if(term_help[i].key2) fprintf(stderr, "[%c] or [%c]", term_help[i].key, term_help[i].key2);
			else fprintf(stderr, "[%c]", term_help[i].key);

			fprintf(stderr, "\t%s\n", term_help[i].desc);
		}
		fprintf(stderr, "\n");
	}
	break;
	case MPG123_FRAME_INDEX_KEY:
	case MPG123_VARIOUS_INFO_KEY:
		if(param.verbose) fprintf(stderr, "\n");
		switch(val) /* because of tolower() ... */
		{
			case MPG123_FRAME_INDEX_KEY:
			print_index(fr);
			{
				long accurate;
				if(mpg123_getstate(fr, MPG123_ACCURATE, &accurate, NULL) == MPG123_OK)
				fprintf(stderr, "Accurate position: %s\n", (accurate == 0 ? "no" : "yes"));
				else
				error1("Unable to get state: %s", mpg123_strerror(fr));
			}
			break;
			case MPG123_VARIOUS_INFO_KEY:
			{
				const char* curdec = mpg123_current_decoder(fr);
				if(curdec == NULL) fprintf(stderr, "Cannot get decoder info!\n");
				else fprintf(stderr, "Active decoder: %s\n", curdec);
			}
		}
	break;
	default:
	  ;
      }
    }
  }
}
コード例 #28
0
ファイル: control_generic.c プロジェクト: 5py/libmpg123
int control_generic (mpg123_handle *fr)
{
	struct timeval tv;
	fd_set fds;
	int n;

	/* ThOr */
	char alive = 1;
	char silent = 0;

	/* responses to stderr for frontends needing audio data from stdout */
	if (param.remote_err)
 		outstream = stderr;
 	else
 		outstream = stdout;
 		
#ifndef WIN32
 	setlinebuf(outstream);
#else /* perhaps just use setvbuf as it's C89 */
	/*
	fprintf(outstream, "You are on Win32 and want to use the control interface... tough luck: We need a replacement for select on STDIN first.\n");
	return 0;
	setvbuf(outstream, (char*)NULL, _IOLBF, 0);
	*/
#endif
	/* the command behaviour is different, so is the ID */
	/* now also with version for command availability */
	fprintf(outstream, "@R MPG123 (ThOr) v7\n");
#ifdef FIFO
	if(param.fifo)
	{
		if(param.fifo[0] == 0)
		{
			error("You wanted an empty FIFO name??");
			return 1;
		}
#ifndef WANT_WIN32_FIFO
		unlink(param.fifo);
		if(mkfifo(param.fifo, 0666) == -1)
		{
			error2("Failed to create FIFO at %s (%s)", param.fifo, strerror(errno));
			return 1;
		}
		debug("going to open named pipe ... blocking until someone gives command");
#endif /* WANT_WIN32_FIFO */
#ifdef WANT_WIN32_FIFO
		control_file = win32_fifo_mkfifo(param.fifo);
#else
		control_file = open(param.fifo,O_RDONLY);
#endif /* WANT_WIN32_FIFO */
		debug("opened");
	}
#endif

	while (alive)
	{
		tv.tv_sec = 0;
		tv.tv_usec = 0;
		FD_ZERO(&fds);
		FD_SET(control_file, &fds);
		/* play frame if no command needs to be processed */
		if (mode == MODE_PLAYING) {
#ifdef WANT_WIN32_FIFO
			n = win32_fifo_read_peek(&tv);
#else
			n = select(32, &fds, NULL, NULL, &tv);
#endif
			if (n == 0) {
				if (!play_frame())
				{
					/* When the track ended, user may want to keep it open (to seek back),
					   so there is a decision between stopping and pausing at the end. */
					if(param.keep_open)
					{
						mode = MODE_PAUSED;
						/* Hm, buffer should be stopped already, shouldn't it? */
						if(param.usebuffer) buffer_stop();
						generic_sendmsg("P 1");
					}
					else
					{
						mode = MODE_STOPPED;
						close_track();
						generic_sendmsg("P 0");
					}
					continue;
				}
				if (init) {
					print_remote_header(fr);
					init = 0;
				}
				if(silent == 0)
				{
					generic_sendstat(fr);
					if(mpg123_meta_check(fr) & MPG123_NEW_ICY)
					{
						char *meta;
						if(mpg123_icy(fr, &meta) == MPG123_OK)
						generic_sendmsg("I ICY-META: %s", meta != NULL ? meta : "<nil>");
					}
				}
			}
		}
		else {
			/* wait for command */
			while (1) {
#ifdef WANT_WIN32_FIFO
				n = win32_fifo_read_peek(NULL);
#else
				n = select(32, &fds, NULL, NULL, NULL);
#endif
				if (n > 0)
					break;
			}
		}

		/*  on error */
		if (n < 0) {
			fprintf(stderr, "Error waiting for command: %s\n", strerror(errno));
			return 1;
		}

		/* read & process commands */
		if (n > 0)
		{
			short int len = 1; /* length of buffer */
			char *cmd, *arg; /* variables for parsing, */
			char *comstr = NULL; /* gcc thinks that this could be used uninitialited... */ 
			char buf[REMOTE_BUFFER_SIZE];
			short int counter;
			char *next_comstr = buf; /* have it initialized for first command */

			/* read as much as possible, maybe multiple commands */
			/* When there is nothing to read (EOF) or even an error, it is the end */
#ifdef WANT_WIN32_FIFO
			len = win32_fifo_read(buf,REMOTE_BUFFER_SIZE);
#else
			len = read(control_file, buf, REMOTE_BUFFER_SIZE);
#endif
			if(len < 1)
			{
#ifdef FIFO
				if(len == 0 && param.fifo)
				{
					debug("fifo ended... reopening");
#ifdef WANT_WIN32_FIFO
					win32_fifo_mkfifo(param.fifo);
#else
					close(control_file);
					control_file = open(param.fifo,O_RDONLY|O_NONBLOCK);
#endif
					if(control_file < 0){ error1("open of fifo failed... %s", strerror(errno)); break; }
					continue;
				}
#endif
				if(len < 0) error1("command read error: %s", strerror(errno));
				break;
			}

			debug1("read %i bytes of commands", len);
			/* one command on a line - separation by \n -> C strings in a row */
			for(counter = 0; counter < len; ++counter)
			{
				/* line end is command end */
				if( (buf[counter] == '\n') || (buf[counter] == '\r') )
				{
					debug1("line end at counter=%i", counter);
					buf[counter] = 0; /* now it's a properly ending C string */
					comstr = next_comstr;

					/* skip the additional line ender of \r\n or \n\r */
					if( (counter < (len - 1)) && ((buf[counter+1] == '\n') || (buf[counter+1] == '\r')) ) buf[++counter] = 0;

					/* next "real" char is first of next command */
					next_comstr = buf + counter+1;

					/* directly process the command now */
					debug1("interpreting command: %s", comstr);
				if(strlen(comstr) == 0) continue;

				/* PAUSE */
				if (!strcasecmp(comstr, "P") || !strcasecmp(comstr, "PAUSE")) {
					if(mode != MODE_STOPPED)
					{	
						if (mode == MODE_PLAYING) {
							mode = MODE_PAUSED;
							if(param.usebuffer) buffer_stop();
							generic_sendmsg("P 1");
						} else {
							mode = MODE_PLAYING;
							if(param.usebuffer) buffer_start();
							generic_sendmsg("P 2");
						}
					} else generic_sendmsg("P 0");
					continue;
				}

				/* STOP */
				if (!strcasecmp(comstr, "S") || !strcasecmp(comstr, "STOP")) {
					if (mode != MODE_STOPPED) {
						if(param.usebuffer)
						{
							buffer_stop();
							buffer_resync();
						}
						close_track();
						mode = MODE_STOPPED;
						generic_sendmsg("P 0");
					} else generic_sendmsg("P 0");
					continue;
				}

				/* SILENCE */
				if(!strcasecmp(comstr, "SILENCE")) {
					silent = 1;
					generic_sendmsg("silence");
					continue;
				}

				if(!strcasecmp(comstr, "T") || !strcasecmp(comstr, "TAG")) {
					generic_sendalltag(fr);
					continue;
				}

				if(!strcasecmp(comstr, "SCAN"))
				{
					if(mode != MODE_STOPPED)
					{
						if(mpg123_scan(fr) == MPG123_OK)
						generic_sendmsg("SCAN done");
						else
						generic_sendmsg("E %s", mpg123_strerror(fr));
					}
					else generic_sendmsg("E No track loaded!");

					continue;
				}

				if(!strcasecmp(comstr, "SAMPLE"))
				{
					off_t pos = mpg123_tell(fr);
					off_t len = mpg123_length(fr);
					/* I need to have portable printf specifiers that do not truncate the type... more autoconf... */
					if(len < 0) generic_sendmsg("E %s", mpg123_strerror(fr));
					else generic_sendmsg("SAMPLE %li %li", (long)pos, (long)len);
					continue;
				}

				if(!strcasecmp(comstr, "SHOWEQ"))
				{
					int i;
					generic_sendmsg("SHOWEQ {");
					for(i=0; i<32; ++i)
					{
						generic_sendmsg("SHOWEQ %i : %i : %f", MPG123_LEFT, i, mpg123_geteq(fr, MPG123_LEFT, i));
						generic_sendmsg("SHOWEQ %i : %i : %f", MPG123_RIGHT, i, mpg123_geteq(fr, MPG123_RIGHT, i));
					}
					generic_sendmsg("SHOWEQ }");
					continue;
				}

				if(!strcasecmp(comstr, "STATE"))
				{
					long val;
					generic_sendmsg("STATE {");
					/* Get some state information bits and display them. */
					if(mpg123_getstate(fr, MPG123_ACCURATE, &val, NULL) == MPG123_OK)
					generic_sendmsg("STATE accurate %li", val);

					generic_sendmsg("STATE }");
					continue;
				}

				/* QUIT */
				if (!strcasecmp(comstr, "Q") || !strcasecmp(comstr, "QUIT")){
					alive = FALSE; continue;
				}

				/* some HELP */
				if (!strcasecmp(comstr, "H") || !strcasecmp(comstr, "HELP")) {
					generic_sendmsg("H {");
					generic_sendmsg("H HELP/H: command listing (LONG/SHORT forms), command case insensitve");
					generic_sendmsg("H LOAD/L <trackname>: load and start playing resource <trackname>");
					generic_sendmsg("H LOADPAUSED/LP <trackname>: load but do not start playing resource <trackname>");
					generic_sendmsg("H LOADLIST <entry> <url>: load a playlist from given <url>, and display its entries, optionally load and play one of these specificed by the integer <entry> (<0: just list, 0: play last track, >0:play track with that position in list)");
					generic_sendmsg("H PAUSE/P: pause playback");
					generic_sendmsg("H STOP/S: stop playback (closes file)");
					generic_sendmsg("H JUMP/J <frame>|<+offset>|<-offset>|<[+|-]seconds>s: jump to mpeg frame <frame> or change position by offset, same in seconds if number followed by \"s\"");
					generic_sendmsg("H VOLUME/V <percent>: set volume in % (0..100...); float value");
					generic_sendmsg("H RVA off|(mix|radio)|(album|audiophile): set rva mode");
					generic_sendmsg("H EQ/E <channel> <band> <value>: set equalizer value for frequency band 0 to 31 on channel %i (left) or %i (right) or %i (both)", MPG123_LEFT, MPG123_RIGHT, MPG123_LR);
					generic_sendmsg("H EQFILE <filename>: load EQ settings from a file");
					generic_sendmsg("H SHOWEQ: show all equalizer settings (as <channel> <band> <value> lines in a SHOWEQ block (like TAG))");
					generic_sendmsg("H SEEK/K <sample>|<+offset>|<-offset>: jump to output sample position <samples> or change position by offset");
					generic_sendmsg("H SCAN: scan through the file, building seek index");
					generic_sendmsg("H SAMPLE: print out the sample position and total number of samples");
					generic_sendmsg("H SEQ <bass> <mid> <treble>: simple eq setting...");
					generic_sendmsg("H PITCH <[+|-]value>: adjust playback speed (+0.01 is 1 %% faster)");
					generic_sendmsg("H SILENCE: be silent during playback (meaning silence in text form)");
					generic_sendmsg("H STATE: Print auxiliary state info in several lines (just try it to see what info is there).");
					generic_sendmsg("H TAG/T: Print all available (ID3) tag info, for ID3v2 that gives output of all collected text fields, using the ID3v2.3/4 4-character names.");
					generic_sendmsg("H    The output is multiple lines, begin marked by \"@T {\", end by \"@T }\".");
					generic_sendmsg("H    ID3v1 data is like in the @I info lines (see below), just with \"@T\" in front.");
					generic_sendmsg("H    An ID3v2 data field is introduced via ([ ... ] means optional):");
					generic_sendmsg("H     @T ID3v2.<NAME>[ [lang(<LANG>)] desc(<description>)]:");
					generic_sendmsg("H    The lines of data follow with \"=\" prefixed:");
					generic_sendmsg("H     @T =<one line of content in UTF-8 encoding>");
					generic_sendmsg("H meaning of the @S stream info:");
					generic_sendmsg("H %s", remote_header_help);
					generic_sendmsg("H The @I lines after loading a track give some ID3 info, the format:");
					generic_sendmsg("H      @I ID3:artist  album  year  comment genretext");
					generic_sendmsg("H     where artist,album and comment are exactly 30 characters each, year is 4 characters, genre text unspecified.");
					generic_sendmsg("H     You will encounter \"@I ID3.genre:<number>\" and \"@I ID3.track:<number>\".");
					generic_sendmsg("H     Then, there is an excerpt of ID3v2 info in the structure");
					generic_sendmsg("H      @I ID3v2.title:Blabla bla Bla");
					generic_sendmsg("H     for every line of the \"title\" data field. Likewise for other fields (author, album, etc).");
					generic_sendmsg("H }");
					continue;
				}

				/* commands with arguments */
				cmd = NULL;
				arg = NULL;
				cmd = strtok(comstr," \t"); /* get the main command */
				arg = strtok(NULL,""); /* get the args */

				if (cmd && strlen(cmd) && arg && strlen(arg))
				{
					/* Simple EQ: SEQ <BASS> <MID> <TREBLE>  */
					if (!strcasecmp(cmd, "SEQ")) {
						double b,m,t;
						int cn;
						if(sscanf(arg, "%lf %lf %lf", &b, &m, &t) == 3)
						{
							/* Consider adding mpg123_seq()... but also, on could define a nicer courve for that. */
							if ((t >= 0) && (t <= 3))
							for(cn=0; cn < 1; ++cn)	mpg123_eq(fr, MPG123_LEFT|MPG123_RIGHT, cn, b);

							if ((m >= 0) && (m <= 3))
							for(cn=1; cn < 2; ++cn) mpg123_eq(fr, MPG123_LEFT|MPG123_RIGHT, cn, m);

							if ((b >= 0) && (b <= 3))
							for(cn=2; cn < 32; ++cn) mpg123_eq(fr, MPG123_LEFT|MPG123_RIGHT, cn, t);

							generic_sendmsg("bass: %f mid: %f treble: %f", b, m, t);
						}
						else generic_sendmsg("E invalid arguments for SEQ: %s", arg);
						continue;
					}

					/* Equalizer control :) (JMG) */
					if (!strcasecmp(cmd, "E") || !strcasecmp(cmd, "EQ")) {
						double e; /* ThOr: equalizer is of type real... whatever that is */
						int c, v;
						/*generic_sendmsg("%s",updown);*/
						if(sscanf(arg, "%i %i %lf", &c, &v, &e) == 3)
						{
							if(mpg123_eq(fr, c, v, e) == MPG123_OK)
							generic_sendmsg("%i : %i : %f", c, v, e);
							else
							generic_sendmsg("E failed to set eq: %s", mpg123_strerror(fr));
						}
						else generic_sendmsg("E invalid arguments for EQ: %s", arg);
						continue;
					}

					if(!strcasecmp(cmd, "EQFILE"))
					{
						equalfile = arg;
						if(load_equalizer(fr) == 0)
						generic_sendmsg("EQFILE done");
						else
						generic_sendmsg("E failed to parse given eq file");

						continue;
					}

					/* SEEK to a sample offset */
					if(!strcasecmp(cmd, "K") || !strcasecmp(cmd, "SEEK"))
					{
						off_t soff;
						char *spos = arg;
						int whence = SEEK_SET;
						if(mode == MODE_STOPPED)
						{
							generic_sendmsg("E No track loaded!");
							continue;
						}

						soff = (off_t) atobigint(spos);
						if(spos[0] == '-' || spos[0] == '+') whence = SEEK_CUR;
						if(0 > (soff = mpg123_seek(fr, soff, whence)))
						{
							generic_sendmsg("E Error while seeking: %s", mpg123_strerror(fr));
							mpg123_seek(fr, 0, SEEK_SET);
						}
						if(param.usebuffer) buffer_resync();

						generic_sendmsg("K %li", (long)mpg123_tell(fr));
						continue;
					}
					/* JUMP */
					if (!strcasecmp(cmd, "J") || !strcasecmp(cmd, "JUMP")) {
						char *spos;
						off_t offset;
						double secs;

						spos = arg;
						if(mode == MODE_STOPPED)
						{
							generic_sendmsg("E No track loaded!");
							continue;
						}

						if(spos[strlen(spos)-1] == 's' && sscanf(arg, "%lf", &secs) == 1) offset = mpg123_timeframe(fr, secs);
						else offset = atol(spos);
						/* totally replaced that stuff - it never fully worked
						   a bit usure about why +pos -> spos+1 earlier... */
						if (spos[0] == '-' || spos[0] == '+') offset += framenum;

						if(0 > (framenum = mpg123_seek_frame(fr, offset, SEEK_SET)))
						{
							generic_sendmsg("E Error while seeking");
							mpg123_seek_frame(fr, 0, SEEK_SET);
						}
						if(param.usebuffer)	buffer_resync();

						generic_sendmsg("J %d", framenum);
						continue;
					}

					/* VOLUME in percent */
					if(!strcasecmp(cmd, "V") || !strcasecmp(cmd, "VOLUME"))
					{
						double v;
						mpg123_volume(fr, atof(arg)/100);
						mpg123_getvolume(fr, &v, NULL, NULL); /* Necessary? */
						generic_sendmsg("V %f%%", v * 100);
						continue;
					}

					/* PITCH (playback speed) in percent */
					if(!strcasecmp(cmd, "PITCH"))
					{
						double p;
						if(sscanf(arg, "%lf", &p) == 1)
						{
							set_pitch(fr, ao, p);
							generic_sendmsg("PITCH %f", param.pitch);
						}
						else generic_sendmsg("E invalid arguments for PITCH: %s", arg);
						continue;
					}

					/* RVA mode */
					if(!strcasecmp(cmd, "RVA"))
					{
						if(!strcasecmp(arg, "off")) param.rva = MPG123_RVA_OFF;
						else if(!strcasecmp(arg, "mix") || !strcasecmp(arg, "radio")) param.rva = MPG123_RVA_MIX;
						else if(!strcasecmp(arg, "album") || !strcasecmp(arg, "audiophile")) param.rva = MPG123_RVA_ALBUM;
						mpg123_volume_change(fr, 0.);
						generic_sendmsg("RVA %s", rva_name[param.rva]);
						continue;
					}

					/* LOAD - actually play */
					if (!strcasecmp(cmd, "L") || !strcasecmp(cmd, "LOAD")){ generic_load(fr, arg, MODE_PLAYING); continue; }

					if (!strcasecmp(cmd, "L") || !strcasecmp(cmd, "LOADLIST")){ generic_loadlist(fr, arg); continue; }

					/* LOADPAUSED */
					if (!strcasecmp(cmd, "LP") || !strcasecmp(cmd, "LOADPAUSED")){ generic_load(fr, arg, MODE_PAUSED); continue; }

					/* no command matched */
					generic_sendmsg("E Unknown command: %s", cmd); /* unknown command */
				} /* end commands with arguments */
				else generic_sendmsg("E Unknown command or no arguments: %s", comstr); /* unknown command */

				} /* end of single command processing */
			} /* end of scanning the command buffer */

			/*
			   when last command had no \n... should I discard it?
			   Ideally, I should remember the part and wait for next
				 read() to get the rest up to a \n. But that can go
				 to infinity. Too long commands too quickly are just
				 bad. Cannot/Won't change that. So, discard the unfinished
				 command and have fingers crossed that the rest of this
				 unfinished one qualifies as "unknown". 
			*/
			if(buf[len-1] != 0)
			{
				char lasti = buf[len-1];
				buf[len-1] = 0;
				generic_sendmsg("E Unfinished command: %s%c", comstr, lasti);
			}
		} /* end command reading & processing */
	} /* end main (alive) loop */
	debug("going to end");
	/* quit gracefully */
#ifndef NOXFERMEM
	if (param.usebuffer) {
		kill(buffer_pid, SIGINT);
		xfermem_done_writer(buffermem);
		waitpid(buffer_pid, NULL, 0);
		xfermem_done(buffermem);
	}
#endif
	debug("closing control");
#ifdef FIFO
#if WANT_WIN32_FIFO
	win32_fifo_close();
#else
	close(control_file); /* be it FIFO or STDIN */
	if(param.fifo) unlink(param.fifo);
#endif /* WANT_WIN32_FIFO */
#endif
	debug("control_generic returning");
	return 0;
}