home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / snews-20.zip / ACTIVE.C next >
C/C++ Source or Header  |  1992-08-09  |  20KB  |  776 lines

  1. /*
  2.     SNEWS 2.0
  3.  
  4.     active.c - routines to manipulate the active and ng files
  5.  
  6.  
  7.     Copyright (C) 1991  John McCombs, Christchurch, NEW ZEALAND
  8.                         john@ahuriri.gen.nz
  9.                         PO Box 2708, Christchurch, NEW ZEALAND
  10.  
  11.     This program is free software; you can redistribute it and/or modify
  12.     it under the terms of the GNU General Public License, version 1, as
  13.     published by the Free Software Foundation.
  14.  
  15.     This program is distributed in the hope that it will be useful,
  16.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.     GNU General Public License for more details.
  19.  
  20.     See the file COPYING, which contains a copy of the GNU General
  21.     Public License.
  22. */
  23.  
  24.  
  25. #include "defs.h"
  26. #include "active.h"
  27.  
  28. extern INFO my_stuff;
  29.  
  30.  
  31. /*
  32.  *  These private variables are used to do all the i/o on the active
  33.  *  file.
  34.  */
  35. static FILE        *active_file;
  36. static ACTIVE      *local_head;
  37. static POST_GROUPS *pg;
  38.  
  39.  
  40.  
  41. /*--------------------------- load the active file --------------------------*/
  42. ACTIVE *load_active_file(void)
  43. {
  44.     /*
  45.      *  This routine opens the active file.  It reads the data, allocating
  46.      *  ACTIVE elements in a linked list.  Returns a pointer to the head of
  47.      *  the linked list.
  48.      */
  49.     char   fn[80], buf[81];
  50.     char   *p;
  51.     ACTIVE *this, *head = NULL ;
  52.     long   posn = 0;
  53.     int    ct = 0;
  54.     int    ct_gp = 0;
  55.  
  56.     /* open the file */
  57.     strcpy(fn, my_stuff.news_dir);
  58.     strcat(fn, "active");
  59.     if ((active_file = fopen(fn, "r+b")) == NULL) {
  60.         fprintf(stderr, "cannot open %s\n", fn);
  61.         exit(1);
  62.     }
  63.  
  64.     /* read and store */
  65.     while (fgets(buf, 80, active_file) != NULL) {
  66.  
  67.         /* exit on ^Z on column 1 */
  68.         if (buf[0] == '\x1A')
  69.             break;
  70.  
  71.         ct++;
  72.  
  73.         if (strlen(buf) > 0) {
  74.  
  75.             if (head == NULL) {
  76.                 head = this = xmalloc(sizeof (ACTIVE));
  77.                 head->last = NULL;
  78.                 head->index = ct_gp;
  79.             } else {
  80.                 ct_gp++;
  81.                 this->next = xmalloc(sizeof (ACTIVE));
  82.                 this->next->last = this;
  83.                 this = this->next;
  84.                 this->index = ct_gp;
  85.             }
  86.  
  87.             if ((this) == NULL) {
  88.                 fprintf(stderr, "cannot allocate memory for active list\n");
  89.                 exit(1);
  90.             }
  91.  
  92.  
  93.             if ((p = strtok(buf, " ")) == NULL) {
  94.                 fprintf(stderr, "active file corrupt at line %d\n", ct);
  95.                 exit(1);
  96.             }
  97.             strcpy(this->group, p);
  98.  
  99.             if ((p = strtok(NULL, " ")) == NULL) {
  100.                 fprintf(stderr, "active file corrupt at line %d\n", ct);
  101.                 exit(1);
  102.             }
  103.             strcpy(this->gp_file, p);
  104.  
  105.             if ((p = strtok(NULL, " ")) == NULL) {
  106.                 fprintf(stderr, "active file corrupt at line %d\n", ct);
  107.                 exit(1);
  108.             }
  109.             this->lo_num = atol(p);
  110.  
  111.             if ((p = strtok(NULL, " ")) == NULL) {
  112.                 fprintf(stderr, "active file corrupt at line %d\n", ct);
  113.                 exit(1);
  114.             }
  115.             this->hi_num = atol(p);
  116.  
  117.             this->num_pos = posn;
  118.             this->read_list = NULL;
  119.         }
  120.  
  121.         posn = ftell(active_file);
  122.     }
  123.  
  124.     this->next = NULL;
  125.     head->groups = ct;
  126.  
  127.     local_head = head;
  128.  
  129.     /* load up the posting list */
  130.     pg = post_group_file();
  131.  
  132.     return(head);
  133. }
  134.  
  135.  
  136.  
  137.  
  138. /*------------------------- close the active file ---------------------------*/
  139. void close_active_file(void)
  140. {
  141.     /*
  142.      *  Close the active file and deallocate the linked list
  143.      */
  144.  
  145.     ACTIVE *this;
  146.  
  147.     this = local_head;
  148.  
  149.     while (this != NULL) {
  150.         local_head = this;
  151.         this = this->next;
  152.         free(local_head);
  153.     }
  154.  
  155.     fclose(active_file);
  156.  
  157.     free_ng();
  158.  
  159. }
  160.  
  161.  
  162. /*------------------------- close the active file ---------------------------*/
  163. void close_active(void)
  164. {
  165.     /*
  166.      *  Close the active file
  167.      */
  168.  
  169.  
  170.     fclose(active_file);
  171.  
  172. }
  173.  
  174.  
  175.  
  176. /*--------------------------- load the newsgroups file --------------------------*/
  177. POST_GROUPS *post_group_file(void)
  178. {
  179.     /*
  180.      *  This routine opens the active file.  It reads the data, allocating
  181.      *  POST_GROUPS elements in a linked list.  Returns a pointer to the head
  182.      *  of the linked list.
  183.      */
  184.     char        fn[80], buf[81], *p;
  185.     POST_GROUPS *this = NULL, *head = NULL ;
  186.     int         ct = 0;
  187.     FILE        *ngf;
  188.  
  189.     /* open the file - if none, retun null, ie no posts allowed */
  190.     strcpy(fn, my_stuff.news_dir);
  191.     strcat(fn, "ng");
  192.     if ((ngf = fopen(fn, "rb")) == NULL) {
  193.         return(NULL);
  194.     }
  195.  
  196.     /* read and store */
  197.     while (fgets(buf, 80, ngf) != NULL) {
  198.  
  199.         /* exit on ^Z on column 1 */
  200.         if (buf[0] == '\x1A')
  201.             break;
  202.  
  203.         ct++;
  204.  
  205.         if (strlen(buf) > 0) {
  206.  
  207.             if (head == NULL) {
  208.                 head = this = xmalloc(sizeof (ACTIVE));
  209.             } else {
  210.                 this->next = xmalloc(sizeof (ACTIVE));
  211.                 this = this->next;
  212.             }
  213.  
  214.             if ((this) == NULL) {
  215.                 fprintf(stderr, "cannot allocate memory for newsgroup list\n");
  216.                 exit(1);
  217.             }
  218.  
  219.             if ((p = strtok(buf, " \n\r\t")) == NULL) {
  220.                 fprintf(stderr, "newsgroup 'ng' file corrupt at line %d\n", ct);
  221.                 exit(1);
  222.             }
  223.  
  224.             strcpy(this->group, p);
  225.             this -> local = isupper(*this -> group);
  226.             strlwr(this -> group);
  227.         }
  228.  
  229.     }
  230.  
  231.     if ( this )
  232.         this->next = NULL;
  233.  
  234.     fclose(ngf);
  235.  
  236.     return(head);
  237. }
  238.  
  239.  
  240.  
  241.  
  242. /*------------------------- close the active file ---------------------------*/
  243. void free_ng()
  244. {
  245.     /*
  246.      *  deallocate the post_groups linked list
  247.      */
  248.  
  249.     POST_GROUPS *this;
  250.  
  251.     this = pg;
  252.  
  253.     while (this != NULL) {
  254.         pg = this;
  255.         this = this->next;
  256.         free(pg);
  257.     }
  258.  
  259.     pg = NULL;
  260.  
  261. }
  262.  
  263.  
  264.  
  265.  
  266. /*------------------------- check group in post list -------------------------*/
  267. int check_valid_post_group(char *ng)
  268. {
  269.     /*
  270.      *  Check a string as a valid newsgroup name.  Returns TRUE if found
  271.      */
  272.  
  273.     POST_GROUPS *this;
  274.  
  275.     this = pg;
  276.  
  277.     while (this != NULL) {
  278.         if (strcmp(ng, this->group) == 0)
  279.             return(TRUE);
  280.         this = this->next;
  281.     }
  282.  
  283.     return (FALSE);
  284. }
  285.  
  286.  
  287. int is_local_group(char *ng)
  288. {
  289.     POST_GROUPS *this;
  290.  
  291.     this = pg;
  292.  
  293.     while (this != NULL) {
  294.         if (strcmp(ng, this->group) == 0)
  295.             return(this->local);
  296.         this = this->next;
  297.     }
  298.  
  299.     return (TRUE);
  300. }
  301.  
  302.  
  303.  
  304.  
  305. /*-------------------- find a newsgroup in active list ----------------------*/
  306. ACTIVE *find_news_group(char *group)
  307. {
  308.     /*
  309.      *  This routine searches the active structure for the specified
  310.      *  newsgroup, and returns a pointer to the entry, or to group
  311.      *  junk if not found.  The search for junk is made via a recursive
  312.      *  call.  Fatal if junk not found
  313.      */
  314.  
  315.     ACTIVE *this;
  316.  
  317.     this = local_head;
  318.  
  319.     while ((this != NULL) && (stricmp(group, this->group) != 0)) {
  320.         this = this->next;
  321.     }
  322.  
  323.     if (this == NULL) {
  324.         if (stricmp(group, "junk") != 0) {
  325.             this = find_news_group("junk");
  326.         } else {
  327.             fprintf(stderr, "active file must have newsgroup junk\n");
  328.             exit(1);
  329.         }
  330.     }
  331.  
  332.     return(this);
  333.  
  334. }
  335.  
  336.  
  337.  
  338.  
  339. /*-------------------------- update active file ---------------------------*/
  340. void update_active_entry(ACTIVE *a)
  341. {
  342.     /*
  343.      *  This routine takes a pointer to an active entry and updates
  344.      *  its data on disk
  345.      */
  346.  
  347.     char buf[(ACTIVE_NUM_LEN*2) + 2];
  348.     int  n;
  349.     long where;
  350.  
  351.     sprintf(buf, "%08ld %08ld", a->lo_num, a->hi_num);
  352.  
  353.     n = (ACTIVE_NUM_LEN*2) + 1;
  354.     where = a->num_pos + strlen(a->group) + 1 + strlen(a->gp_file) + 1;
  355.     fseek(active_file, where, SEEK_SET);
  356.     if (fwrite(buf, 1, n, active_file) != n) {
  357.         fprintf(stderr, "active file update failed for %s\n", a->group);
  358.         exit(1);
  359.     }
  360.  
  361.     fflush(active_file);
  362. }
  363.  
  364.  
  365.  
  366.  
  367.  
  368. /*------------------- make newsgroup name and directory --------------------*/
  369. char *make_news_group_name(char *ng)
  370. {
  371.     /*
  372.      *  This routine takes the newsgroup name, replaces the '.' with
  373.      *  '\' and creates the directory if none exists.  The returned name
  374.      *  has a trailing '\'
  375.      */
  376.  
  377.     static char fn[512];
  378.     ACTIVE *tmp;
  379.  
  380.  
  381.     tmp = find_news_group(ng);
  382.  
  383.     sprintf(fn, "%snewsbase\\%s", my_stuff.news_dir, tmp->gp_file);
  384.  
  385.     return(&fn[0]);
  386. }
  387.  
  388.  
  389.  
  390.  
  391.  
  392. /*-------------------------- save the seen list -------------------------*/
  393. void load_read_list(void)
  394. {
  395.     /*
  396.      *  Load the user's list of seen articles
  397.      */
  398.  
  399.     FILE   *tmp_file;
  400.     ACTIVE *act;
  401.     int    i, continue_flag;
  402.     int    articles;
  403.     char   *a, buf[256], *p, real_name[80];
  404.  
  405.     /* allocate the arrays and set to unread, ie FALSE */
  406.     act = local_head;
  407.     while (act != NULL) {
  408.  
  409.         articles = (int)(act->hi_num - act->lo_num);
  410.         if (articles > 0) {
  411.             a = act->read_list = xmalloc(articles * sizeof(int));
  412.             for (i = 0; i < articles; i++) {
  413.                 *(a+i) = FALSE;
  414.             }
  415.         } else {
  416.             act->read_list = NULL;
  417.         }
  418.         act = act->next;
  419.     }
  420.  
  421.     /* read and process the file - if not present, just carry on */
  422.     strcpy(buf, my_stuff.news_dir);
  423.     strcat(buf, my_stuff.user);
  424.     strcat(buf, ".nrc");
  425.     if ((tmp_file = fopen(buf, "rt")) != NULL) {
  426.  
  427.         continue_flag = FALSE;
  428.         while (fgets(buf, 255, tmp_file) != NULL) {
  429.  
  430.             p = strtok(buf, " \n\r");
  431.  
  432.             if (!continue_flag) {
  433.  
  434.                 strcpy(real_name, p);
  435.                 act = find_news_group(p);
  436.                 articles = (int)(act->hi_num - act->lo_num);
  437.  
  438.                 /* if no articles or unknown group eat the rest */
  439.                 p = strtok(NULL, " \n\r");
  440.  
  441.             }
  442.  
  443.             /* scan the rest of the line getting numbers and setting flags */
  444.             continue_flag = FALSE;
  445.             while (p != NULL) {
  446.  
  447.                 /* check for continuation backslash */
  448.                 if (*p != '\\') {
  449.                     i = (int) (atol(p) - (act->lo_num + 1));
  450.                     if ((i >= 0) && (i < articles) &&
  451.                     ((stricmp(act->group, "junk") != 0) ||
  452.                     (stricmp(real_name, "junk") == 0))) {
  453.                         *((act->read_list)+i) = TRUE;
  454.                     }
  455.                 } else {
  456.                     continue_flag = TRUE;
  457.                     break;
  458.                 }
  459.                 p = strtok(NULL, " \n\r");
  460.             }
  461.         }
  462.  
  463.         fclose(tmp_file);
  464.     }
  465. }
  466.  
  467.  
  468.  
  469.  
  470.  
  471. /*-------------------------- load the seen list -------------------------*/
  472. void save_read_list(void)
  473. {
  474.     /*
  475.      *  Save the user's list of read articles and deallocate storage
  476.      */
  477.  
  478.  
  479.     FILE   *tmp_file;
  480.     ACTIVE *act;
  481.     int    i, articles, ct;
  482.     char   buf[256];
  483.  
  484.     /* open the file */
  485.     strcpy(buf, my_stuff.news_dir);
  486.     strcat(buf, my_stuff.user);
  487.     strcat(buf, ".nrc");
  488.     if ((tmp_file = fopen(buf, "wt")) == NULL) {
  489.         fprintf(stderr, "can't open user's rc file for output\n");
  490.         exit(1);
  491.     }
  492.  
  493.     /* write out the lists and deallocate the arrays */
  494.     act = local_head;
  495.     while (act != NULL) {
  496.  
  497.         articles = (int)(act->hi_num - act->lo_num);
  498.         if (articles > 0) {
  499.             fprintf(tmp_file, "%s ", act->group);
  500.  
  501.             ct = 0;
  502.  
  503.             if (act->read_list)
  504.                 for (i = 0; i < articles; i++) {
  505.                     if(*((act->read_list)+i)) {
  506.                         ct++;
  507.                         fprintf(tmp_file, "%d ", i+act->lo_num+1);
  508.                         if ((ct % 10) == 0)
  509.                             fprintf(tmp_file, "\\ \n");
  510.                     }
  511.                 }
  512.  
  513.             fprintf(tmp_file, "\n");
  514.             if (act->read_list != NULL) {
  515.                 free(act->read_list);
  516.             }
  517.         }
  518.         act = act->next;
  519.     }
  520.  
  521.     fclose(tmp_file);
  522.  
  523. }
  524.  
  525.  
  526.  
  527.  
  528. /*------------------------- load UUPC rc files ---------------------------*/
  529. int load_stuff(void)
  530. {
  531.     /*
  532.      *  Trawl the UUPC files to get the stuff we need - return TRUE
  533.      *  if completed ok
  534.      */
  535.  
  536.     int  res = 0;
  537.     int  i;
  538.     char buf[256], confdir[256];
  539.     char *fn, *p, *v;
  540.     FILE *tmp;
  541.  
  542.  
  543.     /* news base directory */
  544.     if ((fn = getenv("UUPCNEWS")) == NULL) {
  545.         fprintf(stderr, "UUPCNEWS environment variable undefined\n");
  546.         exit(1);
  547.     }
  548.  
  549.     /* give it a trailing \ */
  550.     strcpy(my_stuff.news_dir, fn);
  551.     if (my_stuff.news_dir[ strlen(my_stuff.news_dir)-1 ] != '\\')
  552.         strcat(my_stuff.news_dir, "\\");
  553.  
  554.     /* read the system file first */
  555.     for (i = 0; i < 2; i++) {
  556.  
  557.         /* choose the file to open */
  558.         if (i == 0) {
  559.             fn = getenv("UUPCSYSRC");
  560.             if (fn == NULL) {
  561.                 fprintf(stderr, "Enviroment variable UUPCSYSRC not defined\n");
  562.             }
  563.         } else {
  564.             fn = getenv("UUPCUSRRC");
  565.             if (fn == NULL) {
  566.                 fprintf(stderr, "Enviroment variable UUPCUSRRC not defined\n");
  567.             }
  568.         }
  569.  
  570.  
  571.         if ((tmp = fopen(fn, "rt")) != NULL) {
  572.  
  573.             while (fgets(buf, 255, tmp)) {
  574.                 p = strtok(buf, " =\r\n");
  575.                 if (p && *p != '#') {
  576.  
  577.                     v = strtok(NULL, " =\r\n");
  578.  
  579.                     if (stricmp(p, "confdir") == 0)
  580.                         strcpy(confdir, v);
  581.  
  582.                     if (stricmp(p, "mailserv") == 0) {
  583.                         strcpy(my_stuff.mail_server, v);
  584.                         res++;
  585.                     }
  586.                     if (stricmp(p, "nodename") == 0) {
  587.                         strcpy(my_stuff.my_site, v);
  588.                         res++;
  589.                     }
  590.                     if (stricmp(p, "newsdir") == 0) {
  591.                         strcpy(my_stuff.incoming_dir, v);
  592.                         if (my_stuff.incoming_dir[ strlen(my_stuff.incoming_dir)-1 ] != '\\')
  593.                             strcat(my_stuff.incoming_dir, "\\");
  594.                         res++;
  595.                     }
  596.                     if (stricmp(p, "spooldir") == 0) {
  597.                         strcpy(my_stuff.spool_dir, v);
  598.                         if (my_stuff.spool_dir[ strlen(my_stuff.spool_dir)-1 ] != '\\')
  599.                             strcat(my_stuff.spool_dir, "\\");
  600.                         res++;
  601.                     }
  602.                     if (stricmp(p, "domain") == 0) {
  603.                         strcpy(my_stuff.my_domain, v);
  604.                         res++;
  605.                     }
  606.                     if (stricmp(p, "tempdir") == 0) {
  607.                         strcpy(my_stuff.temp_name, v);
  608.                         res++;
  609.                     }
  610.                     if (stricmp(p, "mailbox") == 0) {
  611.                         strcpy(my_stuff.user, v);
  612.                         res++;
  613.                     }
  614.                     if (stricmp(p, "Signature") == 0) {
  615.                         strcpy(my_stuff.signature, v);
  616.                         res++;
  617.                     }
  618.                     if (stricmp(p, "name") == 0) {
  619.                         strcpy(my_stuff.my_name, v);
  620.                         v = strtok(NULL, " =\r\n");
  621.                         while (v != NULL) {
  622.                             strcat(my_stuff.my_name, " ");
  623.                             strcat(my_stuff.my_name, v);
  624.                             v = strtok(NULL, " =\r\n");
  625.                         }
  626.                         res++;
  627.                     }
  628.                     if (stricmp(p, "Organization") == 0) {
  629.                         strcpy(my_stuff.my_organisation, v);
  630.                         v = strtok(NULL, " =\r\n");
  631.                         while (v != NULL) {
  632.                             strcat(my_stuff.my_organisation, " ");
  633.                             strcat(my_stuff.my_organisation, v);
  634.                             v = strtok(NULL, " =\r\n");
  635.                         }
  636.                         res++;
  637.                     }
  638.                     if (stricmp(p, "Editor") == 0) {
  639.                         strcpy(my_stuff.editor, v);
  640.                         res++;
  641.                         v = strtok(NULL, " =\r\n");
  642.                         while (v != NULL) {
  643.                             strcat(my_stuff.editor, " ");
  644.                             strcat(my_stuff.editor, v);
  645.                             v = strtok(NULL, " =\r\n");
  646.                         }
  647.                     }
  648.                     if (stricmp(p, "Home") == 0) {
  649.                         strcpy(my_stuff.home, v);
  650.                         if (my_stuff.home[ strlen(my_stuff.home)-1 ] != '\\')
  651.                             strcat(my_stuff.home, "\\");
  652.                         res++;
  653.                     }
  654.                 }
  655.             }
  656.             fclose (tmp);
  657.  
  658.         } else {
  659.             fprintf(stderr, "Cannot open %s\n", fn);
  660.         }
  661.     }
  662.  
  663.     if ( (p = getenv("LOGNAME")) != NULL ) {
  664.         struct passwd *pwd;
  665.         if ( (pwd = getpwnam(p, confdir)) != NULL ) {
  666.             strcpy(my_stuff.user, pwd -> pw_name);
  667.             strcpy(my_stuff.home, pwd -> pw_dir);
  668.             strcpy(my_stuff.my_name, pwd -> pw_gecos);
  669.             if (my_stuff.home[ strlen(my_stuff.home)-1 ] != '\\')
  670.                 strcat(my_stuff.home, "\\");
  671.         }
  672.     }
  673.  
  674.     return(res >= 12);
  675. }
  676.  
  677.  
  678.  
  679. /*--------------------------- unpack the batch ------------------------*/
  680. FILE *open_out_file(char *ng)
  681. {
  682.     /*
  683.      *  This routine creates a filename from the newsgroup name.
  684.      *  The active file counter are updated.
  685.      */
  686.  
  687.     ACTIVE *gp;
  688.     char   *fn;
  689.     FILE   *tmp;
  690.  
  691.     gp = find_news_group(ng);
  692.     fn = make_news_group_name(gp->group);
  693.  
  694.     (gp->hi_num)++;
  695.     update_active_entry(gp);
  696.  
  697.     if ((tmp = flockopen(fn, "r+b")) == NULL) {
  698.         fprintf(stderr,"active: cannot open text file %s\n", fn);
  699.         exit(1);
  700.     }
  701.     fseek(tmp, 0, SEEK_END);
  702.  
  703.     return(tmp);
  704. }
  705.  
  706.  
  707. /*--------------------------- unpack the batch ------------------------*/
  708. FILE *open_index_file(char *ng)
  709. {
  710.     /*
  711.      *  This routine open the index file for the newsgroup
  712.      */
  713.  
  714.     ACTIVE *gp;
  715.     char   fnx[256], *fn;
  716.     FILE   *tmp;
  717.  
  718.     /* printf("news: ng found = %s\n", ng); */
  719.     gp = find_news_group(ng);
  720.     fn = make_news_group_name(gp->group);
  721.     sprintf(fnx, "%s.IDX", fn);
  722.  
  723.     if((tmp = flockopen(fnx, "r+b")) == NULL) {
  724.         fprintf(stderr, "active: cannot open index file %s\n", fn);
  725.         exit(1);
  726.     }
  727.     fseek(tmp, 0, SEEK_END);
  728.  
  729.     return(tmp);
  730. }
  731.  
  732.  
  733.  
  734. /*------------------------- post sequence number ----------------------------*/
  735. int post_sequence(void)
  736. {
  737.     /*
  738.      *  Get the sequnce number from the seq file if it exists - if
  739.      *  not create it
  740.      */
  741.  
  742.     FILE *seq_file;
  743.     char fn[256];
  744.     int  seq;
  745.  
  746.     strcpy(fn, my_stuff.news_dir);
  747.     strcat(fn, "nseq");
  748.  
  749.     if ((seq_file = flockopen(fn, "r+t")) != NULL) {
  750.         fscanf(seq_file, "%d", &seq);
  751.         seq++;
  752.         rewind(seq_file);
  753.     } else {
  754.         seq = 0;
  755.         seq_file = flockopen(fn, "wt");
  756.     }
  757.  
  758.     fprintf(seq_file, "%d", seq);
  759.  
  760.     fclose(seq_file);
  761.     return(seq);
  762. }
  763.  
  764.  
  765. /*-------------------------------- safeish malloc --------------------------*/
  766. void *xmalloc(size_t size)
  767. {
  768.     void *p;
  769.     if ((p = malloc(size)) == NULL) {
  770.         fprintf(stderr, "\n\nSORRY - NO MEMORY LEFT \n");
  771.         exit(1);
  772.     }
  773.  
  774.     return(p);
  775. }
  776.