home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / cnews.tar / explode / trbatch.c < prev   
C/C++ Source or Header  |  1994-11-30  |  5KB  |  223 lines

  1. /*
  2.  * transmit batch file management (exploder version)
  3.  */
  4. #include <stdio.h>
  5. #include <errno.h>
  6. #include "fixerrno.h"
  7. #include <sys/types.h>
  8. #include "hdbm.h"
  9. #include "hash.h"
  10. #include "libc.h"
  11. #include "news.h"
  12. /* tunable parameter */
  13. #ifndef NOPENBFS
  14. #define NOPENBFS 250    /* # batchfiles kept open for batching (250 for SunOS 4.1.2 [UUNET]) */
  15. #endif            /* NOPENBFS */
  16. #include "trbatch.h"
  17.  
  18. /* tunable parameters */
  19. #ifndef HASHFILSZ
  20. #define HASHFILSZ (NOPENBFS/2)
  21.             /* # of hash buckets for batch file names */
  22. #endif            /* HASHFILSZ */
  23.  
  24. static HASHTABLE *nmbftbl;        /* name -> batchfile mapping */
  25.  
  26. /*
  27.  * open "name" for appending.
  28.  *
  29.  * see if any batchfile has been assigned to "name" yet.
  30.  * if an attempt to open the batchfile's stream fails, close an arbitrary
  31.  * batchfile stream and retry the open.
  32.  */
  33. struct batchfile *
  34. bfopen(name)
  35. register char *name;
  36. {
  37.     register struct batchfile *bf;
  38.  
  39.     /* malloc_debug(0); */                /* DEBUG */
  40.     bf = bfincache(name);
  41.     if (bf->bf_str == NULL) {
  42.         bf->bf_str = fopenclex(name, "a");    /* silent try */
  43.         if (bf->bf_str == NULL && errno == EMFILE) {
  44.             /* try to free up a descriptor */
  45.             if (bfrclose() != ST_OKAY)
  46.                 return NULL;
  47.             errno = 0;
  48.             warning(
  49.     "had to close a descriptor to reuse it; this should not happen!", "");
  50.                 /* bad input? canthappen? */
  51.         }
  52.         if (bf->bf_str == NULL) {
  53.             /* retry, noisily this time */
  54.             bf->bf_str = fopenwclex(name, "a");
  55.         }
  56.         if (bf->bf_str != NULL)
  57.             bfsetup(bf);
  58.     }
  59.     return bf;
  60. }
  61.  
  62. STATIC
  63. hfinstall(name)
  64. char *name;
  65. {
  66.     register struct batchfile *bf;
  67.  
  68.     if (nmbftbl == NULL)
  69.         nmbftbl = hashcreate(HASHFILSZ, (unsigned (*)())NULL);
  70.     bf = (struct batchfile *)hashfetch(nmbftbl, name);
  71.     if (bf != NULL)
  72.         return;            /* error: name present */
  73.     /* allocate, append & initialise a new entry */
  74.     bf = (struct batchfile *)nemalloc(sizeof *bf);
  75.     (void) memset((char *)bf, 0, sizeof *bf);
  76.     bf->bf_name = strsave(name);    /* NEEDED? */
  77.     bf->bf_str = NULL;    /* paranoia */
  78. #ifdef notdef
  79.     bf->bf_ref = 0;
  80. #endif
  81.     bf->bf_lines = FLUSHEVERY;
  82.     if (!hashstore(nmbftbl, bf->bf_name, (HASHDATUM)bf))
  83.         error("can't store under hash key `%s'", name);    /* canthappen */
  84. }
  85.  
  86. /*
  87.  * returns a batchfile, never NULL, corresponding to name.
  88.  */
  89. struct batchfile *
  90. bfincache(name)
  91. char *name;
  92. {
  93.     register struct batchfile *bf;
  94.  
  95.     bf = bfisopen(name);
  96.     if (bf == NULL) {
  97.         hfinstall(name);
  98.         bf = bfisopen(name);
  99.         if (bf == NULL)
  100.             abort();    /* DEBUG */
  101.     }
  102.     return bf;
  103. }
  104.  
  105. /*
  106.  * write filename, message-id or size on batch file "bf".
  107.  * under the 'f' flag, include the size in bytes of the article
  108.  * after "name" to assist the C news batcher.  under the 'n' flag,
  109.  * write the article's message-id.  afterward, flush "bf" in case
  110.  * the machine crashes before the stream is closed.
  111.  * don't check putc return value for portability; use ferror.
  112.  */
  113. int                            /* boolean */
  114. bfappend(bf, flag, batname, artname, msgid, size)
  115. register struct batchfile *bf;
  116. int flag;
  117. char *batname, *artname, *msgid;
  118. long size;
  119. {
  120.     register FILE *bfstr = bf->bf_str;
  121.  
  122.     if (flag == 'I')
  123.         artname = msgid;            /* cheat */
  124.     if (fputs(artname, bfstr) == EOF)
  125.         return NO;
  126.     if (flag == 'f' && fprintf(bfstr, " %ld", size) == EOF)
  127.         return NO;
  128.     if (flag == 'n') {
  129.         (void) putc(' ', bfstr);
  130.         if (ferror(bfstr) || fputs(msgid, bfstr) == EOF)
  131.             return NO;
  132.     }
  133.     (void) putc('\n', bfstr);
  134.     if (ferror(bfstr) || bfflush(bf) == EOF)
  135.         return NO;
  136.     return YES;        
  137. }
  138.  
  139. /* --- hashing --- */
  140.  
  141. struct closehook {
  142.     short    closedone;
  143.     statust    status;
  144. };
  145.  
  146. STATIC int
  147. closefirst(key, data, hook)
  148. HASHDATUM key, data;
  149. char *hook;
  150. {
  151.     register struct closehook *chp = (struct closehook *)hook;
  152.     register struct batchfile *bf;
  153.  
  154.     if (chp->closedone)
  155.         return;
  156.     bf = (struct batchfile *)data;
  157.     if (bf->bf_str == NULL)
  158.         return;
  159.     chp->status = bfclose(bf);
  160.     chp->closedone = YES;
  161. }
  162.  
  163. STATIC statust
  164. bfrclose()                /* close an arbitrary batchfile */
  165. {
  166.     struct closehook closehook;
  167.     register struct closehook *chp = &closehook;
  168.  
  169.     chp->closedone = NO;
  170.     chp->status = ST_OKAY;
  171.     if (nmbftbl == NULL)
  172.         return chp->status;
  173.     hashwalk(nmbftbl, closefirst, (char *)chp);
  174.     if (!chp->closedone) {
  175.         errno = 0;
  176.         warning("bfrclose couldn't find an open descriptor to close",
  177.             "");    /* canthappen */
  178.     }
  179.     return chp->status;
  180. }
  181.  
  182. STATIC int
  183. closeone(key, data, hook)        /* close a given open batch file */
  184. HASHDATUM key, data;
  185. char *hook;
  186. {
  187.     register struct closehook *chp = (struct closehook *)hook;
  188.     register struct batchfile *bf = (struct batchfile *)data;
  189.  
  190.     if (bf->bf_str != NULL)        /* batch file stream open */
  191.         chp->status |= bfclose(bf);
  192. #ifdef notdef
  193.     bf->bf_ref = 0;
  194. #endif
  195.     if (!hashdelete(nmbftbl, key))
  196.         error("can't delete hash key `%s'", key);    /* canthappen */
  197. }
  198.  
  199. STATIC statust
  200. bfrealclose()                /* close all open batch files */
  201. {
  202.     struct closehook closehook;
  203.     register struct closehook *chp = &closehook;
  204.  
  205.     chp->status = ST_OKAY;
  206.     if (nmbftbl != NULL)
  207.         hashwalk(nmbftbl, closeone, (char *)chp);
  208.     return chp->status;
  209. }
  210.  
  211.  
  212. /*
  213.  * search the batchfile cache for "name"; return the corresponding
  214.  * open master batch file, if any.
  215.  */
  216. STATIC struct batchfile *
  217. bfisopen(name)
  218. char *name;
  219. {
  220.     return nmbftbl == NULL? NULL:
  221.         (struct batchfile *)hashfetch(nmbftbl, name);
  222. }
  223.