/* @(#)buffer.c 17.1.1.1 (ES0-DMD) 01/25/02 17:47:36 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) 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., 675 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .TYPE Module .IDENTIFICATION buffer.c .AUTHOR Francois Ochsenbein [ESO-IPG] .LANGUAGE C .KEYWORDS Buffer / Stack Management .ENVIRONMENT .COMMENTS These routines allow the management of buffers defined as the following BUFFER structure: \begin{TeX} \begin{itemize} \item {\tt char *buf} is the address of the buffer in memory \item {\tt int allocated} is the number of bytes allocated to buf \item {\tt int used} is the present number of bytes used in this buffer \item {\tt int increment} is the number of bytes for automatic expansions \item {\tt offset} is an integer, \eg to perform some searches. It is used for stacking and unstacking. \end{itemize} \end{TeX} .VERSION 1.0 03-Feb-1987: Creation .VERSION 1.1 20-May-1987: Removed bug in mm_set .VERSION 2.0 20-Apr-1988: Changed function names, added stacking facilities. .VERSION 2.1 01-Jun-1988: Added mm_zloc (retrieve a zero item), mm_zindex (retrieve non-zero item) mm_zfree (free the index) .VERSION 2.2 07-Nov-1988: Removed bug in mm_bunst .VERSION 2.3 07-Jun-1991: Be sure an EOS is appended in mm_bapp ----------------------------------------------------------------------------*/ #define DEBUG 0 /* For debugging purposes */ #if DEBUG #define PM_LEVEL LEVEL_STR #endif #define PASCAL_DEF 0 /* Don't include pascalisation ... */ #include /* Standard Definitions */ #include #define FINISH goto FIN /*==========================================================================*/ BUFFER *mm_bopen(size, incr) /*+++ .PURPOSE Allocation of a buffer of a given size .RETURNS Address of allocated buffer, or NULL address if failed, .REMARKS If incr is zero, the buffer cannot be automatically expanded. -------*/ int size; /* IN: The required size (bytes) */ int incr; /* IN: The increment size for expansion (bytes) */ { register BUFFER *b; ENTER("*mm_bopen"); if (size < 0) size = 0; b = MEM_GET(BUFFER,1); b->buf = NULL_PTR(char); b->allocated = size; b->used = 0; b->increment = (incr > 0 ? incr : 0); b->offset = 0; if (b->allocated) b->buf = MEM_GET(char, b->allocated); EXIT_PTR(BUFFER, b); } /*==========================================================================*/ int mm_bfree(b) /*+++ .PURPOSE Free a BUFFER structure --- but ONLY the buffer! .RETURNS OK .REMARKS ---*/ BUFFER *b; /* IN: The buffer to free */ { ENTER("mm_bfree"); if (b) { MEM_FREE(b->buf); b->buf = NULL_PTR(char); b->allocated = 0; b->used = 0; b->offset = 0; } EXIT(OK); } /*==========================================================================*/ int mm_bexp(b, size) /*+++ .PURPOSE Expansion of a buffer .RETURNS OK (1)/ NOK(0) .REMARKS Size of zero implies "use increment" ---*/ BUFFER *b; /* IN: The Buffer to Expand */ int size; /* IN: The required new size (bytes) */ { register char *p; int new_size, status; ENTER("mm_bexp"); new_size = (size > 0 ? size : b->allocated + b->increment); p = MEM_EXP(char, b->buf, new_size); if (p) b->allocated = new_size, b->buf = p, status = OK; else status = NOK; EXIT(status); } /*==========================================================================*/ char *mm_bst(b, record, len) /*+++ .PURPOSE Stack a record into buffer --- The buffer is expanded if necessary .RETURNS Address of stacked record / NULL if error .REMARKS Save offset of previous stacked values. ---*/ BUFFER *b; /* IN: The buffer to free */ char *record; /* IN: record to append */ int len; /* IN: Length of record */ { char *a; ENTER("*mm_bst"); a = mm_ball(b, len + sizeof(int)); if (a) { a += oscopy(a, (char *)(&(b->offset)), sizeof(int)); b->offset = a - b->buf; oscopy(a, record, len); } EXITp(a); } /*==========================================================================*/ char *mm_bunst(b) /*+++ .PURPOSE Unstack a record from buffer. .RETURNS Address of record / NULL .REMARKS ---*/ BUFFER *b; /* IN: The buffer to free */ { char *p; ENTER("*mm_bunst"); if (b->used <= 0) p = NULL_PTR(char); else { b->used = b->offset - sizeof(int); oscopy((char *)(&(b->offset)), b->buf + b->used, sizeof(int)); if (b->used <= 0) p = NULL_PTR(char); else p = b->buf + b->offset; } EXITp(p); } /*==========================================================================*/ char *mm_bapp(b, record, len) /*+++ .PURPOSE Append a record to a buffer --- The buffer is expanded if necessary .RETURNS Address of stored record / NULL if error .REMARKS ---*/ BUFFER *b; /* IN: The buffer to free */ char *record; /* IN: record to append */ int len; /* IN: Length of record */ { char *p; ENTER("*mm_bapp"); /* Get a pointer in buffer, and then copy string * to this buffer */ p = mm_ball(b, len+1); if (p) { oscopy(p, record, len), p[len] = 0; b->used -= 1; } #if DEBUG TRACE_ED_STR2("Buffer: ",b->buf, b->used); #endif EXITp(p); } /*==========================================================================*/ char *mm_ball(b, len) /*+++ .PURPOSE Set a pointer to next available record in buffer. Buffer is expanded if necessary .RETURNS Address of available record / NULL if error .REMARKS ---*/ BUFFER *b; /* IN: The buffer to free */ int len; /* IN: Length of record */ { char *p; int ex; ENTER("*mm_ball"); #if DEBUG TRACE_ED_I("Asks for bytes: ",len); #endif p = NULL_PTR(char); if_not(b) { ERROR("Bad Buffer"); FINISH; } if (len < 0) { ERR_ED_I("Bad Length: ", len); FINISH; } p = (b->buf) + b->used; if (len == 0 ) FINISH; #if DEBUG TRACE_ED_I("Already in buffer: ",b->used); TRACE_ED_STR2("Already in buffer: ",b->buf, b->used); #endif ex = b->used + len - b->allocated; if ( ex > 0) /* Doesn't fit. Expand is required */ { if(b->increment) /* Increment is possible */ { ex = (ex+b->increment-1)/b->increment; ex = ex*b->increment + b->allocated; p = (mm_bexp(b, ex) ? b->buf + b->used : NULL_PTR(char)); } else p = NULL_PTR(char); } else ; FIN: if(p) b->used += len; EXITp(p); } /*==========================================================================*/ char *mm_zfree(b, index, item_len) /*+++ .PURPOSE Free the indexed item. .RETURNS Address of freed item / NULL if bad item .REMARKS No tracing. ---*/ BUFFER *b; /* IN: The buffer to free */ int index; /* IN: Index of item to free */ int item_len; /* IN: Size of 1 item */ { char *p; int o; p = NULL_PTR(char); /* Find first the position */ o = index * item_len; if ( (o < 0) || (o >= b->used) ) FINISH; p = b->buf + o; oscfill(p, item_len, '\0'); FIN: return(p); } /*==========================================================================*/ char *mm_zindex(b, index, item_len) /*+++ .PURPOSE Finds the position of indexed item. Null item is checked. .RETURNS Address of found item / NULL if bad item or is filled with zeroes. .REMARKS No tracing. ---*/ BUFFER *b; /* IN: The buffer to free */ int index; /* IN: Index of item to free */ int item_len; /* IN: Size of 1 item */ { char *p; int o; p = NULL_PTR(char); /* Find first the position */ o = index * item_len; if ( (o < 0) || (o >= b->used) ) FINISH; p = b->buf + o; if (oscskip(p, item_len, '\0') == item_len) /* Filled with zeroes... */ p = NULL_PTR(char); FIN: return(p); } /*==========================================================================*/ char *mm_zloc(b, item_len) /*+++ .PURPOSE Finds the position for a new (free) item. The found position is filled with zeroes, and b->offset is initialized. .RETURNS Address of found item position / NULL if impossible. .REMARKS No tracing. ---*/ BUFFER *b; /* IN: The buffer to free */ int item_len; /* IN: Size of 1 item */ { char *p; /* Look first if space remains. If yes, use it */ if (b->allocated > b->used) { b->offset = b->used; FINISH; } /* Find an position with only zeroes */ for (b->offset = 0; b->offset < b->used; b->offset += item_len) if (oscskip(b->buf + b->offset, item_len, '\0') == item_len) FINISH; /* Last possibility: Must expand the buffer... * Remember that b->offset is correctly set to b->used */ mm_ball(b, item_len); /* Now, initialize the found item */ FIN: if (b->offset < b->allocated) /* It's OK... */ { p = b->buf + b->offset; oscfill(p, item_len, '\0'); if (b->used <= b->offset) b->used = b->offset + item_len; } else { ERROR("Maximum reached."); p = NULL_PTR(char); } return(p); }