#ifndef __proc_output_h__
#define __proc_output_h__

/*
 * The following macros allow one to split calls to a proc read function
 * over multiple calls where a buffer does not suffice a request on the 
 * first call.
 *
 * int
 * proc_read_function (char *page, char **start, off_t off, int count, 
 *                              int *eof, ...)
 * {
 *      DECLARE_PROC_PRINT_VARS (page, count);
 *              
 *      for (...) {
 *              PROC_PRINT ("yada yada\n");   
 *              ...
 *      }       
 *
 *      FINISH_PROC_PRINT (start, eof);
 * }            
 *
 * See also:
 *   http://www.jukie.net/~bart/snippets/proc_output/
 */             

#define DECLARE_PROC_PRINT_VARS(page,count) \
        char *pp_page = page; int pp_count = count;                 \
        off_t pp_pos=0, pp_begin=0, pp_len=0, pp_barrier=0;         \
        int pp_rc=0

#define PROC_PRINT_GET_POINTER()   (pp_page + pp_len)
#define PROC_PRINT_GET_REMAINING() (pp_count - pp_len)

#define PROC_PRINT_ADVANCE(len) do { \
        if (len<0)                                                  \
                goto done;                                          \
        pp_len += len;                                              \
        pp_pos = pp_begin + pp_len;                                 \
        if (pp_pos < off) {                                         \
                pp_len = 0;                                         \
                pp_begin = pp_pos;                                  \
        }                                                           \
        if (pp_pos > off + pp_count)                                \
                goto done;                                          \
} while (0)

#define PROC_PRINT(fmt,args...) do { \
        pp_rc = sprintf (pp_page+pp_len, fmt, ##args);              \
        if (pp_rc < 0) {                                            \
                goto done;                                          \
        }                                                           \
        PROC_PRINT_ADVANCE (pp_rc);                                 \
} while (0)

#define PROC_PRINT_BARRIER_HOLD()    do { \
        pp_barrier = pp_len;                                        \
} while (0)

#define PROC_PRINT_BARRIER_RELEASE() do { \
        pp_barrier = 0;                                             \
} while (0)

#define PROC_PRINT_TERMINATE() do { \
        if (pp_len < pp_count)                                      \
                page [pp_len] = 0;                                  \
        else                                                        \
                page [pp_len-1] = 0;                                \
} while (0)

#define FINISH_PROC_PRINT(start,eof) \
FINISH_PROC_PRINT_BAIL_CONDITION(do{}while(0),start,eof)

#define FINISH_PROC_PRINT_BAIL_CONDITION(do_first, start, eof) do { \
        if (eof) *eof = 1;                                          \
done:                                                               \
        do_first;                                                   \
        if (pp_rc < 0)                                              \
                return pp_rc;                                       \
        if (pp_barrier) {                                           \
                pp_len = pp_barrier;                                \
                pp_pos = pp_begin + pp_len;                         \
        }                                                           \
        if (start)                                                  \
                *start = pp_page + (off - pp_begin);                \
        pp_len -= (off - pp_begin);                                 \
        if (pp_len > pp_count)                                      \
                pp_len = pp_count;                                  \
        if (pp_len < 0)                                             \
                pp_len = 0;                                         \
        return pp_len;                                              \
} while (0)

#endif /* __proc_output_h__ */
