home *** CD-ROM | disk | FTP | other *** search
/ Informática Multimedia: Special Games (Alt) / INFESPGAMES.iso / os2 / backgam / source / util.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-18  |  19.9 KB  |  760 lines

  1. /*************************************************************
  2.  *    ______                                                 *
  3.  *   /     /\  TinyFugue was derived from a client initially *
  4.  *  /   __/  \ written by Anton Rang (Tarrant) and later     *
  5.  *  |  / /\  | modified by Leo Plotkin (Grod).  The early    *
  6.  *  |  |/    | versions of TinyFugue written by Greg Hudson  *
  7.  *  |  X__/  | (Explorer_Bob).  The current version is       *
  8.  *  \ /      / written and maintained by Ken Keys (Hawkeye), *
  9.  *   \______/  who can be reached at kkeys@ucsd.edu.         *
  10.  *                                                           *
  11.  *             No copyright 1992, no rights reserved.        *
  12.  *             Fugue is in the public domain.                *
  13.  *************************************************************/
  14.  
  15. /***********************************
  16.  * Fugue utilities.                *
  17.  *                                 *
  18.  * Written by Greg Hudson and Ken  *
  19.  * Keys.                           *
  20.  *                                 *
  21.  * Uppercase/lowercase table       *
  22.  * Memory allocation routines      *
  23.  * String handling routines        *
  24.  * File utilities                  *
  25.  * Mail checker                    *
  26.  * Cleanup routine                 *
  27.  ***********************************/
  28.  
  29. #include <sys/types.h>
  30. #ifdef MAILDELAY
  31. #include <sys/stat.h>
  32. #endif
  33. #include <ctype.h>
  34. #include <stdio.h>
  35. #include "tf.h"
  36. #include "dstring.h"
  37. #include "util.h"
  38. #include "output.h"
  39. #include "macro.h"
  40. #include "socket.h"
  41. #include "keyboard.h"
  42.  
  43. static int FDECL(cmatch,(char *s1, int c1));
  44. static int FDECL(wmatch,(char *wlist, char **s2));
  45.  
  46. int    FDECL(smatch,(char *s1, char *s2));
  47. int    FDECL(smatch_check,(char *s1));
  48. TFILE *FDECL(tfopen,(char *fname, char *dname, char *mode));
  49. void   NDECL(init_table);
  50. #ifndef DMALLOC
  51. char  *FDECL(dmalloc,(long unsigned size));
  52. char  *FDECL(drealloc,(char *ptr, long unsigned size));
  53. Aline *FDECL(new_aline,(char *str, int attrs));
  54. #endif
  55. void   FDECL(free_aline,(Aline *aline));
  56. #ifdef _STRSTR
  57. char  *FDECL(tf_strstr,(char *s1, char *s2));
  58. #endif
  59. char  *FDECL(cstrchr,(char *s, int c));
  60. char  *FDECL(estrchr,(char *s, int c, int e));
  61. int    FDECL(cstrcmp,(char *s, char *t));
  62. int    FDECL(cstrncmp,(char *s, char *t, int n));
  63. int    FDECL(numarg,(char **str));
  64. char  *FDECL(stripstr,(char *s));
  65. void   FDECL(vSprintf,(Stringp buf, char *fmt, va_list ap));
  66. void   VDECL(oprintf,(char *fmt, ...));
  67. void   VDECL(Sprintf,(Stringp buf, char *fmt, ...));
  68. char   NDECL(getch);
  69. void   FDECL(startopt,(char *args, char *opts));
  70. char   FDECL(nextopt,(char **arg, int *num));
  71. #ifdef MAILDELAY
  72. void   NDECL(check_mail);
  73. #endif
  74. void   NDECL(cleanup);
  75. void   FDECL(die,(char *why));
  76.  
  77. int mail_size = 0;                                    /* size of mail file */
  78. char lowercase_values[128], uppercase_values[128];    /* for lcase(), ucase() */
  79.  
  80. /* A number of non-standard compilers don't properly handle tolower()
  81.  * or toupper() called on a character that wouldn't ordinarily be
  82.  * converted.  Fugue uses its own table (referred to by the ucase()
  83.  * and lcase() macros in util.h) to ensure correct conversions.
  84.  */
  85. void init_table()
  86. {
  87.     int i;
  88.  
  89.     for (i = 0; i < 128; i++) {
  90.         lowercase_values[i] = isupper(i) ? tolower(i) : i;
  91.         uppercase_values[i] = islower(i) ? toupper(i) : i;
  92.     }
  93. }
  94.  
  95. TFILE *tfopen(fname, dname, mode)
  96.     char *fname, *dname, *mode;
  97. {
  98.     smallstr filter;
  99.     int ispipe = FALSE;
  100.     FILE *fp;
  101.     TFILE *result = NULL;
  102.     static Stringp filename, command, suffix;
  103.     static int buffers_initted = FALSE;
  104.  
  105.     if (!buffers_initted) {
  106.         Stringinit(filename);
  107.         Stringinit(command);
  108.         Stringinit(suffix);
  109.     }
  110.  
  111.     if (fname && *fname) {
  112.         Stringcpy(filename, fname);
  113.     } else if (dname) {
  114.         get_macro_body(dname, filename);
  115.     } else {
  116.         oputs("% No filename");
  117.         return NULL;
  118.     }
  119.     Stringexpand(filename);
  120.     if ((fp = fopen(filename->s, mode)) == NULL && errno == ENOENT) {
  121.         get_macro_body("compress_suffix", suffix);
  122.         SStringcat(filename, suffix);
  123.         if ((fp = fopen(filename->s, mode)) != NULL) {
  124.             fclose(fp);
  125.             sprintf(filter, "compress_%s", (*mode == 'r') ? "read" : "write");
  126.             get_macro_body(filter, command);
  127.             Sprintf(command, "\200 %S", filename);
  128.             fp = popen(command->s, mode);
  129.             ispipe = TRUE;
  130.         }
  131.         Stringterm(filename, filename->len - suffix->len);
  132.     }
  133.     if (!fp)
  134.         do_hook(H_LOADFAIL, "%% %S: %s", "%S %s", filename, STRERROR(errno));
  135.     else {
  136.         result = (TFILE*)MALLOC(sizeof(TFILE));
  137.         result->fp = fp;
  138.         result->ispipe = ispipe;
  139.         result->name = STRDUP(filename->s);
  140.     }
  141.     return result;
  142. }
  143.  
  144. /* can't fseek() on a pipe */
  145. int pipejump(file, offset)
  146.     TFILE *file;
  147.     long offset;
  148. {
  149.     char buffer[BUFSIZ];
  150.  
  151.     while ((offset > BUFSIZ) && fread(buffer, sizeof(char), BUFSIZ, file->fp))
  152.         offset -= BUFSIZ;
  153.     return fread(buffer, sizeof(char), offset, file->fp) ? 1 : 0;
  154. }
  155.  
  156. /* Error-checking memory allocation routines.
  157.  */
  158.  
  159. #ifndef DMALLOC
  160. char *dmalloc(size)
  161.     long unsigned size;
  162. {
  163.     char *ret;
  164.  
  165.     if (size == 0) die("% dmalloc(0) called");
  166.     if ((ret = malloc(size)) == NULL) die("% malloc failed");
  167.     return ret;
  168. }
  169.  
  170. char *drealloc(ptr, size)
  171.     char *ptr;
  172.     long unsigned size;
  173. {
  174.     char *ret;
  175.  
  176.     if (size == 0) die("% drealloc(ptr, 0) called");
  177.     if (ret = realloc(ptr, size)) return ret;
  178.     die("% realloc failed");
  179.     return NULL;
  180. }
  181. #endif
  182.  
  183. /* String handlers
  184.  * Some of these are already present in most C libraries, but go by
  185.  * different names or are not always there.  Since they're small, TF
  186.  * simply uses its own routines with non-standard but consistant naming.
  187.  * These are heavily used functions, so speed is favored over simplicity.
  188.  */
  189.  
  190. /* case-insensitive strchr() */
  191. char *cstrchr(s, c)
  192.     register char *s, c;
  193. {
  194.     for (c = lcase(c); *s; s++) if (lcase(*s) == c) return s;
  195.     return (c) ? NULL : s;
  196. }
  197.  
  198. /* c may be escaped by preceeding it with e */
  199. char *estrchr(s, c, e)
  200.     register char *s, c, e;
  201. {
  202.     while (*s) {
  203.         if (*s == c) return s;
  204.         if (*s == e) {
  205.             if (*++s) s++;
  206.         } else s++;
  207.     }
  208.     return NULL;
  209. }
  210.  
  211. #ifdef _STRSTR
  212. char *tf_strstr(s1, s2) 
  213.     register char *s1, *s2;
  214. {
  215.     int len;
  216.  
  217.     for (len = strlen(s2); s1 = strchr(s1, *s2); s1++) {
  218.         if (strncmp(s1, s2, len) == 0) return s1;
  219.     }
  220.     return NULL;
  221. }
  222. #endif
  223.  
  224. /* case-insensitive strcmp() */
  225. int cstrcmp(s, t)
  226.     register char *s, *t;
  227. {
  228.     while (*s && *t && lcase(*s) == lcase(*t)) s++, t++;
  229.     return lcase(*s) - lcase(*t);
  230. }
  231.  
  232. /* case-insensitive strncmp() */
  233. int cstrncmp(s, t, n)
  234.     register char *s, *t;
  235.     int n;
  236. {
  237.     while (n && *s && *t && lcase(*s) == lcase(*t)) s++, t++, n--;
  238.     return (n == 0) ? 0 : lcase(*s) - lcase(*t);
  239. }
  240.  
  241. /* convert numeric argument.  *str will advance to beginning of next */
  242. /* argument, or be NULL for failure. */
  243. int numarg(str)
  244.     char **str;
  245. {
  246.     char *start, *temp;
  247.     for (start = temp = *str; isdigit(*temp); temp++);
  248.     if (temp == *str) {
  249.         *str = NULL;
  250.         return 0;
  251.     }
  252.     for (*str = temp; isspace(**str); (*str)++);
  253.     return atoi(start);
  254. }
  255.  
  256. static int cmatch(s1, c1)
  257.     char *s1, c1;
  258. {
  259.     int result = FALSE;
  260.  
  261.     c1 = lcase(c1);
  262.     if (*s1 == '^') {
  263.         s1++;
  264.         result = TRUE;
  265.     }
  266.     while (*s1) {
  267.         if (*s1 == '\\') s1++;                   /* note that *(s1+1) != '\0' */
  268.         if (*(s1 + 1) == '-' && *(s1 + 2)) {
  269.             char c = *s1, *end = s1 + 2;
  270.  
  271.             if (*end == '\\') end++;
  272.             if (c > *end) {
  273.                 s1++;
  274.                 if (lcase(c) == c1) return result;
  275.             } else {
  276.                 while (c <= *end) if (lcase(c++) == c1) return result;
  277.                 s1 = end + 1;
  278.             }
  279.         } else if (lcase(*s1++) == c1) return result;
  280.     }
  281.     return !result;
  282. }
  283.  
  284. static int wmatch(wlist, s2)
  285.     char *wlist;     /* word list                      */
  286.     char **s2;       /* buffer to match from           */
  287. {
  288.     char *matchstr,  /* which word to find             */
  289.          *strend,    /* end of current word from wlist */
  290.          *matchbuf,  /* where to find from             */
  291.          *bufend;    /* end of match buffer            */
  292.     int  result = 1; /* intermediate result            */
  293.  
  294.     if (!wlist || !*s2) return 1;
  295.     matchbuf = *s2;
  296.     matchstr = wlist;
  297.     if ((bufend = strchr(matchbuf, ' ')) == NULL)
  298.         *s2 += strlen(*s2);
  299.     else
  300.         *(*s2 = bufend) = '\0';
  301.     do {
  302.         if ((strend = estrchr(matchstr, '|', '\\')) != NULL)
  303.             *strend = '\0';
  304.         result = smatch(matchstr, matchbuf);
  305.         if (strend != NULL) *strend++ = '|';
  306.     } while (result && (matchstr = strend) != NULL);
  307.     if (bufend != NULL) *bufend = ' ';
  308.     return result;
  309. }
  310.  
  311. /* smatch_check() should be used on s1 to check pattern syntax before
  312.  * calling smatch().
  313.  */
  314.  
  315. int smatch(s1, s2)
  316.     char *s1, *s2;
  317. {
  318.     char ch, *start = s2;
  319.  
  320.     while (*s1) {
  321.         switch (*s1) {
  322.         case '\\':
  323.             s1++;
  324.             if (lcase(*s1++) != lcase(*s2++)) return 1;
  325.             break;
  326.         case '?':
  327.             if (!*s2++) return 1;
  328.             s1++;
  329.             break;
  330.         case '*':
  331.             while (*s1 == '*' || (*s1 == '?' && *s2++)) s1++;
  332.             if (*s1 == '?') return 1;
  333.             if (*s1 == '{') {
  334.                 if (s2 == start || *(s2 - 1) == ' ')
  335.                     if (!smatch(s1, s2)) return 0;
  336.                 while ((s2 = strchr(s2, ' ')) != NULL)
  337.                     if (!smatch(s1, ++s2)) return 0;
  338.                 return 1;
  339.             } else if (*s1 == '[') {
  340.                 while (*s2) if (!smatch(s1, s2++)) return 0;
  341.                 return 1;
  342.             }
  343.             ch = (*s1 == '\\' && *(s1 + 1)) ? *(s1 + 1) : *s1;
  344.             while ((s2 = cstrchr(s2, ch)) != NULL) {
  345.                 if (!smatch(s1, s2++)) return 0;
  346.             }
  347.             return 1;
  348.         case '[':
  349.             {
  350.                 char *end;
  351.  
  352.                 if (!(end = estrchr(s1, ']', '\\'))) {  /* Shouldn't happen  */
  353.                     oputs("% smatch: unmatched '['");   /* if smatch_check() */
  354.                     return 1;                           /* was used first.   */
  355.                 }
  356.                 *end = '\0';
  357.                 if (cmatch(s1 + 1, *s2++)) {
  358.                     *end = ']';
  359.                     return 1;
  360.                 }
  361.                 *end = ']';
  362.                 s1 = end + 1;
  363.             }
  364.             break;
  365.         case '{':
  366.             if (s2 != start && !isspace(*(s2 - 1))) return 1;
  367.             {
  368.                 char *end;
  369.  
  370.                 if (!(end = estrchr(s1, '}', '\\'))) {  /* Shouldn't happen  */
  371.                     oputs("% smatch: unmatched '{'");   /* if smatch_check() */
  372.                     return 1;                           /* was used first.   */
  373.                 }
  374.                 *end = '\0';
  375.                 if (wmatch(s1 + 1, &s2)) {
  376.                     *end = '}';
  377.                     return 1;
  378.                 }
  379.                 *end = '}';
  380.                 s1 = end + 1;
  381.             }
  382.             break;
  383.         default:
  384.             if(lcase(*s1++) != lcase(*s2++)) return 1;
  385.             break;
  386.         }
  387.     }
  388.     return lcase(*s1) - lcase(*s2);
  389. }
  390.  
  391. /* verify syntax of smatch pattern */
  392. int smatch_check(s1)
  393.     char *s1;
  394. {
  395.     int inword = FALSE;
  396.  
  397.     while (*s1) {
  398.         switch (*s1) {
  399.         case '\\':
  400.             if (*++s1) s1++;
  401.             break;
  402.         case '[':
  403.             if (!(s1 = estrchr(s1, ']', '\\'))) {
  404.                 oputs("% pattern error: unmatched '['");
  405.                 return 0;
  406.             }
  407.             s1++;
  408.             break;
  409.         case '{':
  410.             if (inword) {
  411.                 oputs("% pattern error: nested '{'");
  412.                 return 0;
  413.             }
  414.             inword = TRUE;
  415.             s1++;
  416.             break;
  417.         case '}':
  418.             inword = FALSE;
  419.             s1++;
  420.             break;
  421.         case '?':
  422.         case '*':
  423.         default:
  424.             s1++;
  425.             break;
  426.         }
  427.     }
  428.     if (inword) oputs("% pattern error: unmatched '{'");
  429.     return !inword;
  430. }
  431.  
  432. /* remove leading and trailing spaces */
  433. char *stripstr(s)
  434.     char *s;
  435. {
  436.     char *start, *end;
  437.  
  438.     if (!*s) return 0;
  439.     for (start = s; isspace(*start); start++);
  440.     if (*start) {
  441.         for (end = start + strlen(start) - 1; isspace(*end); end--);
  442.         *++end = '\0';
  443.     } else end = start;
  444.     if (start != s) strcpy(s, start);
  445.     return s;
  446. }
  447.  
  448. /*
  449.  * vSprintf take a format string similar to vsprintf, except:
  450.  * if first char of fmt is \200, args will be appended to buffer;
  451.  * no length formating for %s; %S expects a Stringp argument.
  452.  */
  453.  
  454. void vSprintf(buf, fmt, ap)
  455.     Stringp buf;
  456.     char *fmt;
  457.     va_list ap;
  458. {
  459.     static smallstr lfmt, tempbuf;
  460.     char *p, *q, cval, *sval, *lfmtptr;
  461.     String *Sval;
  462.     int ival;
  463.     unsigned uval;
  464.     double dval;
  465.  
  466.     if (*fmt == '\200') fmt++;
  467.     else Stringterm(buf, 0);
  468.     for (p = fmt; *p; p++) {
  469.         if (*p != '%' || *++p == '%') {
  470.             for (q = p + 1; *q && *q != '%'; q++);
  471.             Stringncat(buf, p, q - p);
  472.             p = q - 1;
  473.             continue;
  474.         }
  475.         lfmtptr = lfmt;
  476.         *lfmtptr++ = '%';
  477.         while (*p && !isalpha(*p)) *lfmtptr++ = *p++;
  478.         *lfmtptr++ = *p;
  479.         *lfmtptr = '\0';
  480.         switch (*p) {
  481.         case 'd':
  482.         case 'i':
  483.             ival = va_arg(ap, int);
  484.             sprintf(tempbuf, lfmt, ival);
  485.             Stringcat(buf, tempbuf);
  486.             break;
  487.         case 'x':
  488.         case 'X':
  489.         case 'u':
  490.         case 'o':
  491.             uval = va_arg(ap, unsigned);
  492.             sprintf(tempbuf, lfmt, uval);
  493.             Stringcat(buf, tempbuf);
  494.             break;
  495.         case 'f':
  496.             dval = va_arg(ap, double);
  497.             sprintf(tempbuf, lfmt, dval);
  498.             Stringcat(buf, tempbuf);
  499.             break;
  500.         case 'c':
  501.             cval = (char)va_arg(ap, int);
  502.             Stringadd(buf, cval);
  503.             break;
  504.         case 's':                       /* Sorry, no length formatting */
  505.             sval = va_arg(ap, char *);
  506.             Stringcat(buf, sval);
  507.             break;
  508.         case 'S':
  509.             Sval = va_arg(ap, String *);
  510.             SStringcat(buf, Sval);
  511.             break;
  512.         default:
  513.             Stringcat(buf, lfmt);
  514.             break;
  515.         }
  516.     }
  517. }
  518.  
  519. /* oprintf */
  520. /* Newlines are not allowed in the format string (this is not enforced). */
  521. /* A newline will appended to the string. */
  522.  
  523. #ifdef STANDARD_C_YES_SIREE
  524. void oprintf(char *fmt, ...)
  525. #else
  526. /* VARARGS */
  527. void oprintf(va_alist)
  528. va_dcl
  529. #endif
  530. {
  531.     va_list ap;
  532. #ifndef STANDARD_C_YES_SIREE
  533.     char *fmt;
  534. #endif
  535.     STATIC_BUFFER(buffer)
  536.  
  537. #ifdef STANDARD_C_YES_SIREE
  538.     va_start(ap, fmt);
  539. #else
  540.     va_start(ap);
  541.     fmt = va_arg(ap, char *);
  542. #endif
  543.     vSprintf(buffer, fmt, ap);
  544.     va_end(ap);
  545.     oputs(buffer->s);
  546. }
  547.  
  548. #ifdef STANDARD_C_YES_SIREE
  549. void Sprintf(String *buffer, char *fmt, ...)
  550. #else
  551. /* VARARGS */
  552. void Sprintf(va_alist)
  553. va_dcl
  554. #endif
  555. {
  556.     va_list ap;
  557. #ifndef STANDARD_C_YES_SIREE
  558.     String *buffer;
  559.     char *fmt;
  560. #endif
  561.  
  562. #ifdef STANDARD_C_YES_SIREE
  563.     va_start(ap, fmt);
  564. #else
  565.     va_start(ap);
  566.     buffer = va_arg(ap, String *);
  567.     fmt = va_arg(ap, char *);
  568. #endif
  569.     vSprintf(buffer, fmt, ap);
  570.     va_end(ap);
  571. }
  572.  
  573. /* Input handlers
  574.  */
  575. char getch()
  576. {
  577.     char c;
  578.     fd_set readers;
  579.  
  580.     FD_ZERO(&readers);
  581.     FD_SET(0, &readers);
  582.     while(select(1, &readers, NULL, NULL, NULL) <= 0);
  583.     read(0, &c, 1);
  584.     return c;
  585. }
  586.  
  587. /* General command option parser
  588.  
  589.    startopt should be called before nextopt.  args is the argument list
  590.    to be parsed, opts is a string containing valid options.  Options which
  591.    take string arguments should be followed by a ':'; options which take
  592.    numeric argumens should be followed by a '#'.  String arguments may be
  593.    omitted.
  594.  
  595.    nextopt returns the next option character.  If option takes a string
  596.    argument, a pointer to it is returned in *arg; an integer argument
  597.    is returned in *num.  If end of options is reached, nextopt returns
  598.    '\0', and *arg points to remainder of argument list.  End of options
  599.    is marked by '\0', '=', '-' by itself, or a word not beggining with
  600.    '-'.  If an invalid option is encountered, an error message is
  601.    printed and '?' is returned.
  602.  
  603.    Option Syntax Rules:
  604.       All options must be preceded by '-'.
  605.       Options may be grouped after a single '-'.
  606.       There must be no space between an option and its argument.
  607.       String option-arguments may be quoted.  Quotes in the arg must be escaped.
  608.       All options must precede operands.
  609.       A '-' with no option may be used to mark the end of the options.
  610.       The relative order of the options should not matter (not enforced).
  611. */
  612.  
  613. static char *argp, *options;
  614. static int inword;
  615.  
  616. void startopt(args, opts)
  617.     char *args, *opts;
  618. {
  619.     argp = args;
  620.     options = opts;
  621.     inword = 0;
  622. }
  623.  
  624. char nextopt(arg, num)
  625.     char **arg;
  626.     int *num;
  627. {
  628.     short error = FALSE;
  629.     char *q, opt;
  630.     STATIC_BUFFER(buffer)
  631.  
  632.     if (!inword) {
  633.         while (isspace(*argp)) argp++;
  634.         if (*argp != '-' || !*++argp || isspace(*argp)) {
  635.             for (*arg = argp; isspace(**arg); ++*arg);
  636.             return '\0';
  637.         }
  638.     } else if (*argp == '=') {        /* '=' marks end, & is part of parms */
  639.         *arg = argp;                  /*... for stuff like  /def -t"foo"=bar */
  640.         return '\0';
  641.     }
  642.     opt = *argp;
  643.     if (opt == ':' || opt == '#') error = TRUE;
  644.     else if ((q = strchr(options, opt)) != NULL) ;
  645.     else if (isdigit(opt) && (q = strchr(options, '0'))) ;
  646.     else error = TRUE;
  647.     if (error) {
  648.         oprintf("%% invalid option: %c", opt);
  649.         return '?';
  650.     }
  651.     if (*q == '0') {
  652.         *num = atoi(argp);
  653.         while (isdigit(*++argp));
  654.         return '0';
  655.     } else if (*++q == ':') {
  656.         Stringterm(buffer, 0);
  657.         if (*++argp == '"') {
  658.             for (argp++; *argp && *argp != '"'; Stringadd(buffer, *argp++))
  659.                 if (*argp == '\\' && (argp[1] == '"' || argp[1] == '\\'))
  660.                     argp++;
  661.             if (!*argp) {
  662.                 oprintf("%% unmatched \" in %c option", opt);
  663.                 return '?';
  664.             } else argp++;
  665.         } else while (*argp && !isspace(*argp)) Stringadd(buffer, *argp++);
  666.         *arg = buffer->s;
  667.     } else if (*q == '#') {
  668.         argp++;
  669.         if (!isdigit(*argp)) {
  670.             oprintf("%% %c option requires numeric argument", opt);
  671.             return '?';
  672.         }
  673.         *num = atoi(argp);
  674.         while (isdigit(*++argp));
  675.     } else argp++;
  676.     inword = (*argp && !isspace(*argp));
  677.     return opt;
  678. }
  679.  
  680. #ifndef DMALLOC
  681. Aline *new_aline(str, attrs)
  682.     char *str;
  683.     int attrs;
  684. {
  685.     Aline *aline;
  686.  
  687.     aline = (Aline *)MALLOC(sizeof(Aline));
  688.     aline->str = str ? STRDUP(str) : NULL;
  689.     aline->attrs = attrs;
  690.     aline->links = 0;
  691.     return aline;
  692. }
  693. #endif
  694.  
  695. void free_aline(aline)
  696.     Aline *aline;
  697. {
  698.     if (!--(aline->links)) {
  699.         FREE(aline->str);
  700.         FREE(aline);
  701.     }
  702. }
  703.  
  704. /* Mail checker */
  705. #ifdef MAILDELAY
  706. void check_mail()
  707. {
  708.     static Stringp fname;
  709.     static int fname_inited = FALSE;
  710.     static int error = FALSE, new = FALSE;
  711.     struct stat statbuf;
  712.  
  713.     if (error) return;
  714.     if (!fname_inited) {
  715.         char *env;
  716.         fname_inited = TRUE;
  717.         Stringinit(fname);
  718.         if (env = getenv("MAIL")) {
  719.             Stringcpy(fname, env);
  720.         } else if (env = getenv("USER")) {
  721.             Sprintf(fname, "%s%s", MAILDIR, env);
  722.         } else {
  723.             oputs("% Warning: can't find name of mail file.");
  724.             error = TRUE;
  725.             return;
  726.         }
  727.     }
  728.     if (stat(fname->s, &statbuf) == -1) {
  729.         if (mail_size) put_mail(mail_size = 0);
  730.     } else {
  731.         if (statbuf.st_size > mail_size) {
  732.             put_mail(TRUE);
  733.             if (new) do_hook(H_MAIL, "%% You have new mail.", "");
  734.         } else if (mail_size != 0 && statbuf.st_size == 0)
  735.             put_mail(FALSE);
  736.         mail_size = statbuf.st_size;
  737.     }
  738.     new = TRUE;
  739. }
  740. #endif
  741.  
  742. /* Cleanup and error routines. */
  743. void cleanup()
  744. {
  745.     extern int screen_setup;
  746.  
  747.     cooked_echo_mode();
  748.     disconnect_all();
  749.     if (screen_setup) fix_screen();
  750. }
  751.  
  752. void die(why)
  753.     char *why;
  754. {
  755.     cleanup();
  756.     puts(why);
  757.     exit(1);
  758. }
  759.  
  760.