예제 #1
0
파일: hash.c 프로젝트: andreiw/polaris
/*.......................................................................
 * Delete a hash-table.
 *
 * Input:
 *  hash   HashTable *  The hash table to be deleted.
 * Output:
 *  return HashTable *  The deleted hash table (always NULL).
 */
HashTable *_del_HashTable(HashTable *hash)
{
  if(hash) {
/*
 * Clear and delete the bucket array.
 */
    if(hash->bucket) {
      _clear_HashTable(hash);
      free(hash->bucket);
      hash->bucket = NULL;
    };
/*
 * Delete application data.
 */
    if(hash->del_fn)
      hash->del_fn(hash->app_data);
/*
 * If the hash table was allocated from an internal free-list, delete
 * it and the hash table by deleting the free-list. Otherwise just
 * return the hash-table to the external free-list.
 */
    if(hash->internal_mem)
      _del_HashMemory(hash->mem, 1);
    else
      hash = (HashTable *) _del_FreeListNode(hash->mem->hash_memory, hash);
  };
  return NULL;
}
예제 #2
0
/*.......................................................................
 * Free a string that was previously returned by _new_StringMemString().
 *
 * Input:
 *  sm      StringMem *  The free-list from which the string was originally
 *                       allocated.
 *  s            char *  The string to be returned to the free-list, or NULL.
 * Output:
 *  return       char *  Always NULL.
 */
char *_del_StringMemString(StringMem *sm, char *s)
{
  int was_malloc;  /* True if the string originally came from malloc() */
/*
 * Is there anything to be deleted?
 */
  if(s && sm) {
/*
 * Retrieve the true string pointer. This is one less than the one
 * returned by _new_StringMemString() because the first byte of the
 * allocated memory is reserved by _new_StringMemString as a flag byte
 * to say whether the memory was allocated from the free-list or directly
 * from malloc().
 */
    s--;
/*
 * Get the origination flag.
 */
    was_malloc = s[0];
    if(was_malloc) {
      free(s);
      s = NULL;
      sm->nmalloc--;
    } else {
      s = (char *) _del_FreeListNode(sm->fl, s);
    };
  };
  return NULL;
}
예제 #3
0
파일: hash.c 프로젝트: andreiw/polaris
/*.......................................................................
 * Private function used to delete a hash-table node.
 * The node must have been removed from its list before calling this
 * function.
 *
 * Input:
 *  hash   HashTable *  The table for which the node was originally
 *                      allocated.
 *  node    HashNode *  The node to be deleted.
 * Output:
 *  return  HashNode *  The deleted node (always NULL).
 */
static HashNode *_del_HashNode(HashTable *hash, HashNode *node)
{
  if(node) {
    node->symbol.name = _del_StringMemString(hash->mem->string_memory,
					    node->symbol.name);
/*
 * Call the user-supplied data-destructor if provided.
 */
    if(node->symbol.data && node->symbol.del_fn)
      node->symbol.data = node->symbol.del_fn(hash->app_data,
					      node->symbol.code,
					      node->symbol.data);
/*
 * Return the node to the free-list.
 */
    node->next = NULL;
    node = (HashNode *) _del_FreeListNode(hash->mem->node_memory, node);
  };
  return NULL;
}
예제 #4
0
/*.......................................................................
 * Get a new directory reader object from the cache.
 *
 * Input:
 *  ef        ExpandFile *  The pathname expansion resource object.
 *  pathname  const char *  The pathname of the directory.
 * Output:
 *  return       DirNode *  The cache entry of the new directory reader,
 *                          or NULL on error. On error, ef->errmsg will
 *                          contain a description of the error.
 */
static DirNode *ef_open_dir(ExpandFile *ef, const char *pathname)
{
  char *errmsg = NULL;  /* An error message from a called function */
  DirNode *node;        /* The cache node used */
/*
 * Get the directory reader cache.
 */
  DirCache *cache = &ef->cache;
/*
 * Extend the cache if there are no free cache nodes.
 */
  if(!cache->next) {
    node = (DirNode *) _new_FreeListNode(cache->mem);
    if(!node) {
      snprintf(ef->errmsg, sizeof(ef->errmsg),
	       "Insufficient memory to open a new directory");
      return NULL;
    };
/*
 * Initialize the cache node.
 */
    node->next = NULL;
    node->prev = NULL;
    node->dr = NULL;
/*
 * Allocate a directory reader object.
 */
    node->dr = _new_DirReader();
    if(!node->dr) {
      snprintf(ef->errmsg, sizeof(ef->errmsg),
	       "Insufficient memory to open a new directory");
      node = (DirNode *) _del_FreeListNode(cache->mem, node);
      return NULL;
    };
/*
 * Append the node to the cache list.
 */
    node->prev = cache->tail;
    if(cache->tail)
      cache->tail->next = node;
    else
      cache->head = node;
    cache->next = cache->tail = node;
  };
/*
 * Get the first unused node, but don't remove it from the list yet.
 */
  node = cache->next;
/*
 * Attempt to open the specified directory.
 */
  if(_dr_open_dir(node->dr, pathname, &errmsg)) {
    strncpy(ef->errmsg, errmsg, ERRLEN);
    ef->errmsg[ERRLEN] = '\0';
    return NULL;
  };
/*
 * Now that we have successfully opened the specified directory,
 * remove the cache node from the list, and relink the list around it.
 */
  cache->next = node->next;
  if(node->prev)
    node->prev->next = node->next;
  else
    cache->head = node->next;
  if(node->next)
    node->next->prev = node->prev;
  else
    cache->tail = node->prev;
  node->next = node->prev = NULL;
/*
 * Return the successfully initialized cache node to the caller.
 */
  return node;
}
예제 #5
0
/*.......................................................................
 * Write as many characters as possible from the start of a character
 * queue via a given output callback function, removing those written
 * from the queue.
 *
 * Input:
 *  cq        GlCharQueue *  The queue to write characters from.
 *  write_fn  GL_WRITE_FN *  The function to call to output characters,
 *                           or 0 to simply discard the contents of the
 *                           queue.
 *  data             void *  Anonymous data to pass to write_fn().
 * Output:
 *  return   GlFlushState    The status of the flush operation:
 *                             GLQ_FLUSH_DONE  -  The flush operation
 *                                                completed successfully.
 *                             GLQ_FLUSH_AGAIN -  The flush operation
 *                                                couldn't be completed
 *                                                on this call. Call this
 *                                                function again when the
 *                                                output channel can accept
 *                                                further output.
 *                             GLQ_FLUSH_ERROR    Unrecoverable error.
 */
GlqFlushState _glq_flush_queue(GlCharQueue *cq, GlWriteFn *write_fn,
			       void *data)
{
/*
 * Check the arguments.
 */
  if(!cq) {
    errno = EINVAL;
    return GLQ_FLUSH_ERROR;
  };
/*
 * If possible keep writing until all of the chained buffers have been
 * emptied and removed from the list.
 */
  while(cq->buffers.head) {
/*
 * Are we looking at the only node in the list?
 */
    int is_tail = cq->buffers.head == cq->buffers.tail;
/*
 * How many characters more than an exact multiple of the buffer-segment
 * size have been added to the buffer so far?
 */
    int nmodulo = cq->ntotal % GL_CQ_SIZE;
/*
 * How many characters of the buffer segment at the head of the list
 * have been used? Note that this includes any characters that have
 * already been flushed. Also note that if nmodulo==0, this means that
 * the tail buffer segment is full. The reason for this is that we
 * don't allocate new tail buffer segments until there is at least one
 * character to be added to them.
 */
    int nhead = (!is_tail || nmodulo == 0) ? GL_CQ_SIZE : nmodulo;
/*
 * How many characters remain to be flushed from the buffer
 * at the head of the list?
 */
    int nbuff = nhead - (cq->nflush % GL_CQ_SIZE);
/*
 * Attempt to write this number.
 */
    int nnew = write_fn(data, cq->buffers.head->bytes +
			cq->nflush % GL_CQ_SIZE, nbuff);
/*
 * Was anything written?
 */
    if(nnew > 0) {
/*
 * Increment the count of the number of characters that have
 * been flushed from the head of the queue.
 */
      cq->nflush += nnew;
/*
 * If we succeded in writing all of the contents of the current
 * buffer segment, remove it from the queue.
 */
      if(nnew == nbuff) {
/*
 * If we just emptied the last node left in the list, then the queue is
 * now empty and should be reset.
 */
	if(is_tail) {
	  _glq_empty_queue(cq);
	} else {
/*
 * Get the node to be removed from the head of the list.
 */
	  CqCharBuff *node = cq->buffers.head;
/*
 * Make the node that follows it the new head of the queue.
 */
	  cq->buffers.head = node->next;
/*
 * Return it to the freelist.
 */
	  node = (CqCharBuff *) _del_FreeListNode(cq->bufmem, node);
	};
      };
/*
 * If the write blocked, request that this function be called again
 * when space to write next becomes available.
 */
    } else if(nnew==0) {
      return GLQ_FLUSH_AGAIN;
/*
 * I/O error.
 */
    } else {
      _err_record_msg(cq->err, "Error writing to terminal", END_ERR_MSG);
      return GLQ_FLUSH_ERROR;
    };
  };
/*
 * To get here the queue must now be empty.
 */
  return GLQ_FLUSH_DONE;
}