/*      
 * libir by David Johnson
 * Copyright (C) 1998-2008 David Johnson 
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 */

/**************************************************************************
 * 
 * misc stuff
 * 
 **************************************************************************/

#define max2(a,b) ( (a > b) ? a : b )
#define min2(a,b) ( (a < b) ? a : b )
#define max3(a,b,c) ( max2(a,max2(b,c)) )
#define min3(a,b,c) ( min2(a,min2(b,c)) )
#define between(min,a,max) ( max2(min2(a,max),min) )
#define floor(v,f) ( (v) - ((v) % (f)) )
#define ceiling(v,c) ( (v) + (((v) % (c)) ? ((c) - ((v) % (c))) : 0) )

extern int set_socket_nonblocking (int s, int nonblock);
extern int is_fd_readable(int fd);
extern int is_fd_writeable(int fd);


/**************************************************************************
 * 
 * ir_list - Doublely linked list
 * 
 **************************************************************************/

struct ir_list_item
{
  struct ir_list_item *next;
  struct ir_list_item *prev;
};

struct ir_list
{
  int size;
  struct ir_list_item *head;
  struct ir_list_item *tail;
};

/*
 * === ir_list_alloc() ===
 * Allocate 'size' user data.
 * Returns a pointer to user data (already zeroed)
 */
extern void* ir_list_alloc(unsigned int size);

/*
 * === ir_list_alloc_data() ===
 * Allocate 'size' user data
 * Copies 'data' to allocated space
 * Returns a pointer to user data (already copied)
 */
extern void* ir_list_alloc_data(const void *data, unsigned int size);

/*
 * === ir_list_add() ===
 * Calls ir_list_alloc() 
 * Calls ir_list_insert_tail()
 */
extern void* ir_list_add(struct ir_list *list, unsigned int size);

/*
 * === ir_list_add_data() ===
 * Calls ir_list_alloc_data()
 * Calls ir_list_insert_tail()
 */
extern void* ir_list_add_data(struct ir_list *list, const void *data, unsigned int size);

/*
 * === ir_list_free() ===
 * Free user data.
 */
extern void ir_list_free(void *item);

/*
 * === ir_list_delete() ===
 * Calls ir_list_remove()
 * Calls ir_list_free()
 * Returns pointer to next user data in 'list'
 */
extern void* ir_list_delete(struct ir_list *list, void *item);

/*
 * === ir_list_delete_all() ===
 * Remotes all items from 'list'
 * Free's all user data for removed items
 */
extern void ir_list_delete_all(struct ir_list *list);

/*
 * === ir_list_remove() ===
 * Removes 'item' from 'list'
 * Returns pointer to next user data in 'list'
 */
extern void* ir_list_remove(struct ir_list *list, void *item);

/*
 * === ir_list_insert*() ===
 * Inserts 'item' into 'list' at various locations
 */
extern void ir_list_insert_head(struct ir_list *list, void *item);
extern void ir_list_insert_tail(struct ir_list *list, void *item);
extern void ir_list_insert_before(struct ir_list *list, void *item, void *before_this);
extern void ir_list_insert_after(struct ir_list *list, void *item, void *after_this);

/*
 * === ir_list_get*() ===
 * Gets an item from 'list' at various locations
 * Returns pointer to user data
 */
extern void* ir_list_get_head(const struct ir_list *list);
extern void* ir_list_get_tail(const struct ir_list *list);
extern void* ir_list_get_next(const void *cur);
extern void* ir_list_get_prev(const void *cur);
extern void* ir_list_get_next_nth(void *cur, int n); /* cur + nth */
extern void* ir_list_get_prev_nth(void *cur, int n); /* cur - nth */
extern void* ir_list_get_nth(struct ir_list *list, int nth); /* zero based n */

/*
 * === ir_list_search_unsorted_for() ===
 * Searches an unsorted list for an item that matches 'match'
 * A match is defined as cmpfunc() returning 0.
 * Returns pointer to user data of any match, NULL on no match
 */
extern void* ir_list_search_unsorted_for(struct ir_list *list,
                                         const void *match,
                                         int (*cmpfunc)(void *userdata, const void *a, const void *b),
                                         void *userdata);

/*
 * === ir_list_search_sorted_for() ===
 * Searches a sorted list for an item that matches 'match'
 * A match is defined as cmpfunc() returning 0.
 * Returns pointer to user data of first match
 * If no match found, returns NULL and sets *best to the item just
 * prior to where the match would be, or NULL if item would be at
 * the head of the list.
 */
extern void* ir_list_search_sorted_for(struct ir_list *list,
                                       const void *match,
                                       void **best,
                                       int (*cmpfunc)(void *userdata, const void *a, const void *b),
                                       void *userdata);

/*
 * === ir_list_size() ===
 * Returns the number of items in 'list'
 */
extern int ir_list_size(const struct ir_list *list);

/*
 * === ir_list_sort() ===
 * Sorts list by doing a set of comparisons between each item
 * cmpfunc should return <0 if a<b, 0 if a==b, or >0 if a>b
 * userdata is passed to cmpfunc on each call
 */
extern void ir_list_sort(struct ir_list *list,
                         int (*cmpfunc)(void *userdata, const void *a, const void *b),
                         void *userdata);

/*
 * === ir_list_cmpfunc_memcmp() ===
 * Comparison function for memory type user data.
 * user data must contain a blob at offset 0 of specified length
 * length is pointed to with 'userdata' as (size_t*)
 */
extern int ir_list_cmpfunc_memcmp(void *userdata, const void *a, const void *b);

/*
 * === ir_list_cmpfunc_string() ===
 * Comparison function for string type user data.
 * user data must contain a null-terminated string at offset (int*)userdata
 */
extern int ir_list_cmpfunc_string(void *userdata, const void *a, const void *b);

/*
 * === ir_list_cmpfunc_int() ===
 * Comparison function for int type user data.
 * user data must contain an 'int' at offset (int*)userdata
 */
extern int ir_list_cmpfunc_int(void *userdata, const void *a, const void *b);

/*
 * === ir_list_cmpfunc_unsigned_int() ===
 * Comparison function for unsigned int type user data.
 * user data must contain an 'unsigned int' at offset (int*)userdata
 */
extern int ir_list_cmpfunc_unsigned_int(void *userdata, const void *a, const void *b);


/**************************************************************************
 * 
 * ir_boutput - Buffered non-blocking writes
 * 
 **************************************************************************/

/* buffer output flags */
#define BOUTPUT_NO_FLUSH       1
#define BOUTPUT_NO_LIMIT       2

/* Buffer Output options */
#define IR_BOUTPUT_SEGMENT_SIZE    (1<<10)
#define IR_BOUTPUT_MAX_SEGMENTS    (64)

struct ir_boutput_segment
{
  unsigned int begin;
  unsigned int end;
  char buffer[IR_BOUTPUT_SEGMENT_SIZE];
};

struct ir_boutput
{
  int fd;
  int flags;
  struct ir_list segments;
  unsigned int count_written;
  unsigned int count_flushed;
  unsigned int count_dropped;
};

extern int ir_boutput_write(struct ir_boutput *bout, const void *buffer, int buffer_len);
extern int ir_boutput_need_flush(struct ir_boutput *bout);
extern int ir_boutput_attempt_flush(struct ir_boutput *bout);
extern void ir_boutput_init(struct ir_boutput *bout, int fd, int flags);
extern void ir_boutput_set_flags(struct ir_boutput *bout, int flags);
extern void ir_boutput_delete(struct ir_boutput *bout);


/* End of File */






