home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume26 / cook-1.4 / part09 < prev    next >
Text File  |  1993-05-03  |  85KB  |  4,419 lines

  1. Newsgroups: comp.sources.unix
  2. From: pmiller@bmr.gov.au (Peter Miller)
  3. Subject: v26i217: cook-1.4 - a file construction tool (like "make"), Part09/11
  4. Sender: unix-sources-moderator@efficacy.home.vix.com
  5. Approved: WhoAmI@efficacy.home.vix.com
  6.  
  7. Submitted-By: pmiller@bmr.gov.au (Peter Miller)
  8. Posting-Number: Volume 26, Issue 217
  9. Archive-Name: cook-1.4/part09
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 9 (of 11)."
  18. # Contents:  cook/lex.c cook/os.c cooktime/date.y
  19. # Wrapped by vixie@efficacy.home.vix.com on Tue May  4 01:36:42 1993
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'cook/lex.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'cook/lex.c'\"
  23. else
  24. echo shar: Extracting \"'cook/lex.c'\" \(26740 characters\)
  25. sed "s/^X//" >'cook/lex.c' <<'END_OF_FILE'
  26. X/*
  27. X *    cook - file construction tool
  28. X *    Copyright (C) 1990, 1991, 1992, 1993 Peter Miller.
  29. X *    All rights reserved.
  30. X *
  31. X *    This program is free software; you can redistribute it and/or modify
  32. X *    it under the terms of the GNU General Public License as published by
  33. X *    the Free Software Foundation; either version 2 of the License, or
  34. X *    (at your option) any later version.
  35. X *
  36. X *    This program is distributed in the hope that it will be useful,
  37. X *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  38. X *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  39. X *    GNU General Public License for more details.
  40. X *
  41. X *    You should have received a copy of the GNU General Public License
  42. X *    along with this program; if not, write to the Free Software
  43. X *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  44. X *
  45. X * MANIFEST: functions to perform lexical analysis on cookbooks
  46. X *
  47. X * This file contains the lexical analyser for the cookbook parser.
  48. X * A known bug is that it processes # control lines even within comments.
  49. X * Another bug is that comments vanish: they should be replaced by a single
  50. X * space.
  51. X */
  52. X
  53. X#include <stddef.h>
  54. X#include <string.h>
  55. X#include <stdlib.h>
  56. X#include <stdio.h>
  57. X
  58. X#include <error.h>
  59. X#include <expr.h>
  60. X#include <hashline.h>
  61. X#include <id.h>
  62. X#include <lex.h>
  63. X#include <mem.h>
  64. X#include <option.h>
  65. X#include <s-v-arg.h>
  66. X#include <stmt.h>
  67. X#include <trace.h>
  68. X#include <parse.gen.h>    /* must be last */
  69. X#include <hashline.gen.h> /* must be last */
  70. X
  71. X
  72. X/*
  73. X * Meta types
  74. X */
  75. X#define NORMAL    1
  76. X#define SLOSHED    2
  77. X#define WHITE    3
  78. X
  79. X/*
  80. X */
  81. X#define BEFORE    (1<<0)
  82. X#define AFTER    (1<<1)
  83. X#define SINGLE    (1<<2)
  84. X
  85. X#define HASHLINE_ESCAPE ('#' ^ 0x80)
  86. X#define UNQUOTED_WORD 32767
  87. X#define EOLN 32766
  88. X
  89. X
  90. Xtypedef struct meta_ty meta_ty;
  91. Xstruct meta_ty
  92. X{
  93. X    int        m_type;        /* meta character "type" info    */
  94. X    int        m_char;        /* meta character actual value    */
  95. X    int        m_flag;        /* meta character flags        */
  96. X};
  97. X
  98. Xtypedef struct lex_ty lex_ty;
  99. Xstruct lex_ty
  100. X{
  101. X    string_ty    *l_name;    /* name of file being analysed    */
  102. X    FILE        *l_file;    /* open file structure of the file */
  103. X    int        l_line;        /* the line number we are up to    */
  104. X    meta_ty        l_mback;    /* backup for meta chars    */
  105. X    lex_ty        *l_chain;    /* file this one is an insert from */
  106. X    short        l_bol;
  107. X};
  108. X
  109. Xtypedef struct stracc stracc;
  110. Xstruct    stracc
  111. X{
  112. X    size_t        sa_max;        /* size of string accum buffer    */
  113. X    size_t        sa_len;        /* number of chars accumulated    */
  114. X    char        *sa_buf;    /* the string accum buffer    */
  115. X    int        sa_inuse;
  116. X};
  117. X
  118. Xstatic    lex_ty        *root;        /* root of insert list        */
  119. Xstatic    stracc        saroot;        /* root of string accum list    */
  120. Xstatic    int        errcnt;        /* count of errors to date    */
  121. Xstatic    int        mode;        /* what lex mode we are in    */
  122. Xstatic    int        state;
  123. Xstatic    int        passing;
  124. Xstatic    int        catted;
  125. X
  126. X
  127. X/*
  128. X * NAME
  129. X *    lex_initialize - look for keywords
  130. X *
  131. X * SYNOPSIS
  132. X *    int lex_initialize(void);
  133. X *
  134. X * DESCRIPTION
  135. X *    The lex_initialize function adds all the keywords to the symbol table.
  136. X *
  137. X * CAVEAT
  138. X *    The keywords are intentionally case sensitive.
  139. X *    Assumes that str_initialize has already been called.
  140. X */
  141. X
  142. Xvoid
  143. Xlex_initialize()
  144. X{
  145. X    typedef struct keyword_ty keyword_ty;
  146. X    struct keyword_ty
  147. X    {
  148. X        char        *k_name;
  149. X        int        k_token;
  150. X        id_class_ty    k_class;
  151. X    };
  152. X
  153. X    static keyword_ty keyword[] =
  154. X    {
  155. X        { ":",        COLON,        ID_CLASS_PARSE_KEYWORD,    },
  156. X        { ";",        SEMICOLON,    ID_CLASS_PARSE_KEYWORD,    },
  157. X        { "=",        EQUALS,        ID_CLASS_PARSE_KEYWORD,    },
  158. X        { "[",        LBRAK,        ID_CLASS_HASH_KEYWORD,    },
  159. X        { "[",        LBRAK,        ID_CLASS_PARSE_KEYWORD,    },
  160. X        { "]",        RBRAK,        ID_CLASS_HASH_KEYWORD,    },
  161. X        { "]",        RBRAK,        ID_CLASS_PARSE_KEYWORD,    },
  162. X        { "data",    DATA,        ID_CLASS_PARSE_KEYWORD,    },
  163. X        { "elif",    HASH_ELIF,    ID_CLASS_HASH_KEYWORD,    },
  164. X        { "else",    ELSE,        ID_CLASS_PARSE_KEYWORD,    },
  165. X        { "else",    HASH_ELSE,    ID_CLASS_HASH_KEYWORD,    },
  166. X        { "endif",    HASH_ENDIF,    ID_CLASS_HASH_KEYWORD,    },
  167. X        { "fail",    FAIL,        ID_CLASS_PARSE_KEYWORD,    },
  168. X        { "if",        HASH_IF,    ID_CLASS_HASH_KEYWORD,    },
  169. X        { "if",        IF,        ID_CLASS_PARSE_KEYWORD,    },
  170. X        { "ifdef",    HASH_IFDEF,    ID_CLASS_HASH_KEYWORD,    },
  171. X        { "ifndef",    HASH_IFNDEF,    ID_CLASS_HASH_KEYWORD,    },
  172. X        { "include",    HASH_INCLUDE,    ID_CLASS_HASH_KEYWORD,    },
  173. X        { "loop",    LOOP,        ID_CLASS_PARSE_KEYWORD,    },
  174. X        { "loopstop",    LOOPSTOP,    ID_CLASS_PARSE_KEYWORD,    },
  175. X        { "pragma",    HASH_PRAGMA,    ID_CLASS_HASH_KEYWORD,    },
  176. X        { "set",    SET,        ID_CLASS_PARSE_KEYWORD,    },
  177. X        { "then",    THEN,        ID_CLASS_PARSE_KEYWORD,    },
  178. X        { "unsetenv",    UNSETENV,    ID_CLASS_PARSE_KEYWORD,    },
  179. X        { "{"/*}*/,    LBRACE,        ID_CLASS_PARSE_KEYWORD,    },
  180. X        { /*{*/"}",    RBRACE,        ID_CLASS_PARSE_KEYWORD,    },
  181. X    };
  182. X    keyword_ty    *kp;
  183. X
  184. X    trace(("init_reserved()\n{\n"/*}*/));
  185. X    passing = 1;
  186. X    for (kp = keyword; kp < ENDOF(keyword); ++kp)
  187. X    {
  188. X        string_ty    *s;
  189. X
  190. X        s = str_from_c(kp->k_name);
  191. X        id_assign(s, kp->k_class, &kp->k_token);
  192. X        str_free(s);
  193. X    }
  194. X    trace((/*{*/"}\n"));
  195. X}
  196. X
  197. X
  198. X/*
  199. X * NAME
  200. X *    lex_open - open a file for lexical analysis
  201. X *
  202. X * SYNOPSIS
  203. X *    void lex_open(string_ty *filename);
  204. X *
  205. X * DESCRIPTION
  206. X *    Lex_open opens a file for lexical analysis
  207. X *    (it is also used to open include files).
  208. X *
  209. X * RETURNS
  210. X *    void
  211. X */
  212. X
  213. Xvoid
  214. Xlex_open(filename)
  215. X    string_ty    *filename;
  216. X{
  217. X    lex_ty        *new;
  218. X
  219. X    trace(("lex_open(filename = %08lX)\n{\n"/*}*/, filename));
  220. X    trace_string(filename->str_text);
  221. X    for (new = root; new; new = new->l_chain)
  222. X    {
  223. X        if (str_equal(filename, new->l_name))
  224. X        {
  225. X            lex_error("%s: recursive include", filename->str_text);
  226. X            return;
  227. X        }
  228. X    }
  229. X    new = (lex_ty *)mem_alloc_clear(sizeof(lex_ty));
  230. X    new->l_name = str_copy(filename);
  231. X    new->l_file = fopen(filename->str_text, "r");
  232. X    if (!new->l_file)
  233. X        nfatal("cookbook \"%s\"", filename->str_text);
  234. X    new->l_line = 1;
  235. X    new->l_bol = 1;
  236. X    new->l_chain = root;
  237. X    root = new;
  238. X    trace((/*{*/"}\n"));
  239. X}
  240. X
  241. X
  242. X/*
  243. X * NAME
  244. X *    lex_close - closes a file which was open for lexical analysis
  245. X *
  246. X * SYNOPSIS
  247. X *    void lex_close(void);
  248. X *
  249. X * DESCRIPTION
  250. X *    Lex_close closes a file previously opened for lexical analysis.
  251. X *
  252. X * CAVEAT
  253. X *    Lex_open must have been previously used to open the file.
  254. X */
  255. X
  256. Xvoid
  257. Xlex_close()
  258. X{
  259. X    lex_ty        *old;
  260. X
  261. X    trace(("lex_close()\n{\n"/*}*/));
  262. X    assert(root);
  263. X    old = root;
  264. X    fclose(root->l_file);
  265. X    root = old->l_chain;
  266. X    if (!root && errcnt)
  267. X        exit(1);
  268. X    str_free(old->l_name);
  269. X    free(old);
  270. X    trace((/*{*/"}\n"));
  271. X}
  272. X
  273. X
  274. X/*
  275. X * NAME
  276. X *    illeof - conplain about an illegal end-of-file
  277. X *
  278. X * SYNOPSIS
  279. X *    void illeof(void);
  280. X *
  281. X * DESCRIPTION
  282. X *    Illeof is used to complain about illegal end-of-file.
  283. X *    This may occu in several places.
  284. X *
  285. X * CAVEAT
  286. X *    It does not return.
  287. X */
  288. X
  289. Xstatic void illeof _((void));
  290. X
  291. Xstatic void
  292. Xilleof()
  293. X{
  294. X    lex_error("unexpected end of file");
  295. X    exit(1);
  296. X}
  297. X
  298. X
  299. X/*
  300. X * NAME
  301. X *    byte - get a byte from the input stream
  302. X *
  303. X * SYNOPSIS
  304. X *    int byte(void);
  305. X *
  306. X * DESCRIPTION
  307. X *    Byte return the next byte from the input stream, or EOF
  308. X *    If the end of the outermost file is reached.
  309. X *    It detechs the end of include files and closes them transparently.
  310. X *
  311. X * CAVEAT
  312. X *    Lex_open must have been called previously.
  313. X */
  314. X
  315. Xstatic int byte _((void));
  316. X
  317. Xstatic int
  318. Xbyte()
  319. X{
  320. X    int        c;
  321. X        
  322. X    trace(("byte()\n{\n"/*}*/));
  323. X    for (;;)
  324. X    {
  325. X        assert(root);
  326. X        c = fgetc(root->l_file);
  327. X        if (c != EOF)
  328. X            break;
  329. X        if (ferror(root->l_file))
  330. X            nfatal("%s", root->l_name->str_text);
  331. X        if (!root->l_chain)
  332. X            break;
  333. X        lex_close();
  334. X    }
  335. X    if ((c < ' ' || c > '~') && c != EOF && !strchr("\t\n\f", c))
  336. X    {
  337. X        lex_error("illegal '\\%o' character", (unsigned char)c);
  338. X        c = ' ';
  339. X    }
  340. X    if (mode != LM_DATA && root->l_bol && c == '#')
  341. X        c = HASHLINE_ESCAPE;
  342. X    if (c == '\n')
  343. X    {
  344. X        root->l_bol = 1;
  345. X        root->l_line++;
  346. X    }
  347. X    else
  348. X    {
  349. X        if (!strchr(" \t\f", c))
  350. X            root->l_bol = 0;
  351. X    }
  352. X    trace_short(root->l_bol);
  353. X    trace(("return '%c';\n", c));
  354. X    trace((/*{*/"}\n"));
  355. X    return c;
  356. X}
  357. X
  358. X
  359. X/*
  360. X * NAME
  361. X *    byte_undo - push back a character
  362. X *
  363. X * SYNOPSIS
  364. X *    void byte_undo(int c);
  365. X *
  366. X * Description
  367. X *    Byte_undo pushes a byte back onto the input stream.
  368. X *
  369. X * CAVEAT
  370. X *    Only one byte may be pushed back at any one time.
  371. X */
  372. X
  373. Xstatic void byte_undo _((int));
  374. X
  375. Xstatic void
  376. Xbyte_undo(c)
  377. X    int        c;
  378. X{
  379. X    trace(("byte_undo(c = '%c')\n{\n"/*}*/, c));
  380. X    assert(root);
  381. X    switch (c)
  382. X    {
  383. X    case EOF:
  384. X        break;
  385. X
  386. X    case '\n':
  387. X        root->l_line--;
  388. X    default:
  389. X        ungetc(c, root->l_file);
  390. X        break;
  391. X    }
  392. X    trace((/*{*/"}\n"));
  393. X}
  394. X
  395. X
  396. X/*
  397. X * NAME
  398. X *    sa_open - start accumulating a string.
  399. X *
  400. X * SYNOPSIS
  401. X *    void sa_open(void);
  402. X *
  403. X * DESCRIPTION
  404. X *    Sa_open begins accumulating a string for the lexical analyser.
  405. X *    This allows virtually infinite length constructs within the
  406. X *    lexical analyser.
  407. X */
  408. X
  409. Xstatic void sa_open _((void));
  410. X
  411. Xstatic void
  412. Xsa_open()
  413. X{
  414. X    trace(("sa_open()\n{\n"/*}*/));
  415. X    assert(!saroot.sa_inuse);
  416. X    saroot.sa_inuse = 1;
  417. X    saroot.sa_len = 0;
  418. X    trace((/*{*/"}\n"));
  419. X}
  420. X
  421. X
  422. X/*
  423. X * NAME
  424. X *    sa_char - add a character to the accumulating string
  425. X *
  426. X * SYNOPSIS
  427. X *    void sa_char(int c);
  428. X *
  429. X * DESCRIPTION
  430. X *    Sa_char adds a character to the accumulating string.
  431. X *
  432. X * CAVEAT
  433. X *    Sa_open must have been called previously.
  434. X */
  435. X
  436. Xstatic void sa_char _((int));
  437. X
  438. Xstatic void
  439. Xsa_char(c)
  440. X    int        c;
  441. X{
  442. X    trace(("sa_char(c = '%c')\n{\n"/*}*/, c));
  443. X    assert(saroot.sa_inuse);
  444. X    if (saroot.sa_len >= saroot.sa_max)
  445. X    {
  446. X        saroot.sa_max += 128;
  447. X        if (!saroot.sa_buf)
  448. X            saroot.sa_buf = (char *)mem_alloc(saroot.sa_max);
  449. X        else
  450. X            mem_change_size((char **)&saroot.sa_buf, saroot.sa_max);
  451. X    }
  452. X    saroot.sa_buf[saroot.sa_len++] = c;
  453. X    trace((/*{*/"}\n"));
  454. X}
  455. X
  456. X
  457. X/*
  458. X * NAME
  459. X *    sa_close - finish accumulating a string
  460. X *
  461. X * SYNOPSIS
  462. X *    string_ty *sa_close(void);
  463. X *
  464. X * DESCRIPTION
  465. X *    Sa_close finished accumulating a string and
  466. X *    returns a pointer to the string in dynamic memory.
  467. X *
  468. X * CAVEAT
  469. X *    Sa_open must have been called previously.
  470. X *
  471. X *    The value returned by this function is allocated in dynamic memory.
  472. X *    It is the responsibility of the caller to ensure that it is freed when
  473. X *    finished with, by a call to str_free().
  474. X */
  475. X
  476. Xstatic string_ty *sa_close _((void));
  477. X
  478. Xstatic string_ty *
  479. Xsa_close()
  480. X{
  481. X    string_ty    *val;
  482. X
  483. X    trace(("sa_close()\n{\n"/*}*/));
  484. X    assert(saroot.sa_inuse);
  485. X    val = str_n_from_c(saroot.sa_buf, saroot.sa_len);
  486. X    saroot.sa_inuse = 0;
  487. X    trace(("return %08lX;\n", val));
  488. X    trace((/*{*/"}\n"));
  489. X    return val;
  490. X}
  491. X
  492. X
  493. X/*
  494. X * NAME
  495. X *    sa_mark - mark place when accumulating a string
  496. X *
  497. X * SYNOPSIS
  498. X *    size_t sa_mark(void);
  499. X *
  500. X * DESACRIPTION
  501. X *    Sa_mark returns an indicator as to where the string being accumulated
  502. X *    is up to.
  503. X *
  504. X * CAVEAT
  505. X *    Sa_open must have been called previously.
  506. X *    Do not use the returned value for anything other than passing to
  507. X *    sa_goto as an argument.
  508. X */
  509. X
  510. Xstatic size_t sa_mark _((void));
  511. X
  512. Xstatic size_t
  513. Xsa_mark()
  514. X{
  515. X    assert(saroot.sa_inuse);
  516. X    return (saroot.sa_len);
  517. X}
  518. X
  519. X
  520. X/*
  521. X * NAME
  522. X *    sa_goto - shorten the accumulated string
  523. X *
  524. X * SYNOPSIS
  525. X *    void sa_goto(size_t mark);
  526. X *
  527. X * DESACRIPTION
  528. X *    Sa_goto shotens the accumulating string to a point
  529. X *    previously determined by sa_mark.
  530. X *
  531. X * CAVEAT
  532. X *    Sa_open must have been called previously.
  533. X *    The mark argument must have previously been returned by sa_mark,
  534. X *    and sa_close not called in the interim.
  535. X */
  536. X
  537. Xstatic void sa_goto _((size_t));
  538. X
  539. Xstatic void
  540. Xsa_goto(n)
  541. X    size_t        n;
  542. X{
  543. X    assert(saroot.sa_inuse);
  544. X    assert(n <= saroot.sa_len);
  545. X    saroot.sa_len = n;
  546. X}
  547. X
  548. X
  549. X/*
  550. X * NAME
  551. X *    meta_repn - mata_ty representation
  552. X *
  553. X * SYNOPSIS
  554. X *    char *meta_repn(meta_ty*);
  555. X *
  556. X * DESCRIPTION
  557. X *    The meta_repn function is used to produce a readable representation of
  558. X *    a mata_ty value.
  559. X *
  560. X * RETURNS
  561. X *    char* - a pointer to ta C string.
  562. X *
  563. X * CAVEAT
  564. X *    This function is only available when the DEBUG symbol is #define'd.
  565. X */
  566. X
  567. X#ifdef DEBUG
  568. X
  569. Xstatic char *meta_repn _((meta_ty *));
  570. X
  571. Xstatic char *
  572. Xmeta_repn(val)
  573. X    meta_ty        *val;
  574. X{
  575. X    static char *type[] =
  576. X    {
  577. X        "0",
  578. X        "NORMAL",
  579. X        "SLOSHED",
  580. X        "WHITE",
  581. X    };
  582. X    static char *flag[] =
  583. X    {
  584. X        "0",
  585. X        "BEFORE",
  586. X        "AFTER",
  587. X        "AFTER | BEFORE",
  588. X        "SINGLE",
  589. X        "SINGLE | BEFORE",
  590. X        "SINGLE | AFTER",
  591. X        "SINGLE | AFTER | BEFORE",
  592. X    };
  593. X    static char    buffer[100];
  594. X    char        buf2[20];
  595. X    char        buf3[10];
  596. X
  597. X    if (val->m_type >= 0 && val->m_type < SIZEOF(type))
  598. X        strcpy(buf2, type[val->m_type]);
  599. X    else
  600. X        sprintf(buf2, "%d", val->m_type);
  601. X    switch (val->m_char)
  602. X    {
  603. X    default:
  604. X        if (val->m_char >= ' ' && val->m_char <= '~')
  605. X        {
  606. X            buf3[0] = val->m_char;
  607. X            buf3[1] = 0;
  608. X        }
  609. X        else
  610. X            sprintf(buf3, "\\%03o", (unsigned char)val->m_char);
  611. X        break;
  612. X
  613. X    case '\'':
  614. X    case '\\':
  615. X        buf3[0] = '\\';
  616. X        buf3[1] = val->m_char;
  617. X        buf3[2] = 0;
  618. X        break;
  619. X    }
  620. X    sprintf
  621. X    (
  622. X        buffer,
  623. X        "{m_char = '%s', m_type = %s, m_flag = %s}",
  624. X        buf3,
  625. X        buf2,
  626. X        flag[val->m_flag]
  627. X    );
  628. X    return buffer;
  629. X}
  630. X
  631. X#endif
  632. X
  633. X
  634. X/*
  635. X * NAME
  636. X *    meta - fetch and classify a character
  637. X *
  638. X * SYNOPSIS
  639. X *    void meta(meta_ty*);
  640. X *
  641. X * DESCRIPTION
  642. X *    Meta fetches and classifies a character from the input stream.
  643. X *    The classification may be 'mode' dependent.
  644. X *
  645. X *    This is the point at which escaped newlines and comments are replaced
  646. X *    by a single space.
  647. X *
  648. X * CAVEAT
  649. X *    Lex_open must have been called previously.
  650. X */
  651. X
  652. Xstatic void meta _((meta_ty *));
  653. X
  654. Xstatic void
  655. Xmeta(val)
  656. X    meta_ty        *val;
  657. X{
  658. X    trace(("meta(val = %08lX)\n{\n"/*}*/, val));
  659. X    assert(root);
  660. X    if (root->l_mback.m_type)
  661. X    {
  662. X        *val = root->l_mback;
  663. X        root->l_mback.m_type = 0;
  664. X    }
  665. X    else
  666. X    {
  667. X        switch (val->m_char = byte())
  668. X        {
  669. X        default:
  670. X            val->m_type = NORMAL;
  671. X            val->m_flag = BEFORE | AFTER;
  672. X            break;
  673. X    
  674. X        case EOF:
  675. X            val->m_type = EOF;
  676. X            val->m_flag = SINGLE;
  677. X            break;
  678. X    
  679. X        case '=':
  680. X        case ';':
  681. X        case ':':
  682. X        case '{'/*}*/:
  683. X        case /*{*/'}':
  684. X            switch (mode)
  685. X            {
  686. X            default:
  687. X                val->m_type = NORMAL;
  688. X                val->m_flag = SINGLE;
  689. X                break;
  690. X    
  691. X            case LM_DATA:
  692. X            case LM_SQUOTE:
  693. X            case LM_DQUOTE:
  694. X                val->m_type = NORMAL;
  695. X                val->m_flag = BEFORE | AFTER;
  696. X                break;
  697. X            }
  698. X            break;
  699. X    
  700. X        case '['/*]*/:
  701. X            switch (mode)
  702. X            {
  703. X            default:
  704. X                val->m_flag = BEFORE | SINGLE;
  705. X                break;
  706. X    
  707. X            case LM_SQUOTE:
  708. X            case LM_DQUOTE:
  709. X                val->m_flag = BEFORE | AFTER;
  710. X            }
  711. X            val->m_type = NORMAL;
  712. X                break;
  713. X    
  714. X        case /*[*/']':
  715. X            val->m_type = NORMAL;
  716. X            switch (mode)
  717. X            {
  718. X            default:
  719. X                val->m_flag = AFTER | SINGLE;
  720. X                break;
  721. X    
  722. X            case LM_DATA:
  723. X            case LM_SQUOTE:
  724. X            case LM_DQUOTE:
  725. X                val->m_flag = BEFORE | AFTER;
  726. X                break;
  727. X            }
  728. X            break;
  729. X    
  730. X        case ' ':
  731. X        case '\t':
  732. X        case '\n':
  733. X        case '\f':
  734. X            switch (mode)
  735. X            {
  736. X            default:
  737. X                val->m_type = WHITE;
  738. X                val->m_flag = SINGLE;
  739. X                break;
  740. X    
  741. X            case LM_SQUOTE:
  742. X            case LM_DQUOTE:
  743. X            case LM_DATA:
  744. X                val->m_type = NORMAL;
  745. X                val->m_flag = BEFORE | AFTER;
  746. X                break;
  747. X            }
  748. X            break;
  749. X    
  750. X        case '\\':
  751. X            switch (val->m_char = byte())
  752. X            {
  753. X            case EOF:
  754. X                illeof();
  755. X    
  756. X            case '\n':
  757. X                val->m_char = ' ';
  758. X                val->m_type = WHITE;
  759. X                val->m_flag = SINGLE;
  760. X                break;
  761. X    
  762. X            case '0':
  763. X            case '1':
  764. X            case '2':
  765. X            case '3':
  766. X            case '4':
  767. X            case '5':
  768. X            case '6':
  769. X            case '7':
  770. X                {
  771. X                    int     count;
  772. X                    int     c;
  773. X    
  774. X                    c = val->m_char;
  775. X                    val->m_char = 0;
  776. X                    for (count = 0; count < 3; count++)
  777. X                    {
  778. X                        val->m_char = val->m_char * 8 + c - '0';
  779. X                        c = byte();
  780. X                        if (c < '0' || c > '7')
  781. X                        {
  782. X                            byte_undo(c);
  783. X                            break;
  784. X                        }
  785. X                    }
  786. X                    val->m_type = SLOSHED;
  787. X                    val->m_flag = BEFORE | AFTER;
  788. X                }
  789. X                break;
  790. X    
  791. X            default:
  792. X                {
  793. X                    char    *cp;
  794. X    
  795. X                    cp = strchr("b\bf\fn\nr\rt\t", val->m_char);
  796. X                    if (cp)
  797. X                        val->m_char = cp[1];
  798. X                    val->m_type = SLOSHED;
  799. X                    val->m_flag = BEFORE | AFTER;
  800. X                }
  801. X                break;
  802. X            }
  803. X            break;
  804. X    
  805. X        case '/':
  806. X            switch (mode)
  807. X            {
  808. X            default:
  809. X                {
  810. X                    int     c;
  811. X                    int     gate;
  812. X                    int     count;
  813. X    
  814. X                    if ((c = byte()) != '*')
  815. X                    {
  816. X                        byte_undo(c);
  817. X                        val->m_type = NORMAL;
  818. X                        val->m_flag = BEFORE | AFTER;
  819. X                        break;
  820. X                    }
  821. X                    gate = 0;
  822. X                    count = 1;
  823. X                    while (count)
  824. X                    {
  825. X                        switch (c = byte())
  826. X                        {
  827. X                        default:
  828. X                        case '\n':
  829. X                        case '\t':
  830. X                        case '\f':
  831. X                            gate = 0;
  832. X                            break;
  833. X    
  834. X                        case EOF:
  835. X                            illeof();
  836. X    
  837. X                        case '*':
  838. X                            if (gate == 1)
  839. X                            {
  840. X                                /*
  841. X                                 * nested comment start
  842. X                                 *
  843. X                                 * should a warning be issued?
  844. X                                 */
  845. X                                count++;
  846. X                                gate = 0;
  847. X                            }
  848. X                            else
  849. X                                gate = 2;
  850. X                            break;
  851. X    
  852. X                        case '/':
  853. X                            if (gate == 2)
  854. X                            {
  855. X                                count--;
  856. X                                gate = 0;
  857. X                            }
  858. X                            else
  859. X                                gate = 1;
  860. X                            break;
  861. X                        }
  862. X                    }
  863. X                    val->m_char = ' ';
  864. X                    val->m_type = WHITE;
  865. X                    val->m_flag = SINGLE;
  866. X                }
  867. X                break;
  868. X    
  869. X            case LM_DATA:
  870. X            case LM_SQUOTE:
  871. X            case LM_DQUOTE:
  872. X                val->m_type = NORMAL;
  873. X                val->m_flag = BEFORE | AFTER;
  874. X                break;
  875. X            }
  876. X            break;
  877. X        }
  878. X    }
  879. X    trace(("*val = %s;\n", meta_repn(val)));
  880. X    trace((/*{*/"}\n"));
  881. X}
  882. X
  883. X
  884. X/*
  885. X * NAME
  886. X *    meta_undo - push back a character
  887. X *
  888. X * SYNOPSIS
  889. X *    void meta_undo(meta_ty*);
  890. X *
  891. X * DESCRIPTION
  892. X *    Meta_undo is used to temporarily push back a character
  893. X *    from the input stream.
  894. X *
  895. X * CAVEAT
  896. X *    Only one character may be pushed back at any one time.
  897. X */
  898. X
  899. Xstatic void meta_undo _((meta_ty *));
  900. X
  901. Xstatic void
  902. Xmeta_undo(val)
  903. X    meta_ty        *val;
  904. X{
  905. X    assert(root);
  906. X    assert(!root->l_mback.m_type);
  907. X    root->l_mback = *val;
  908. X}
  909. X
  910. X
  911. X/*
  912. X * NAME
  913. X *    lex_error - print a file location specific error message
  914. X *
  915. X * SYNOPSIS
  916. X *    void lex_error(char *s, ...);
  917. X *
  918. X * DESCRIPTION
  919. X *    Lex_error prints a file location specific error message.
  920. X *    If too many errors pass through here, cook will give up.
  921. X */
  922. X
  923. X/*VARARGS1*/
  924. Xvoid
  925. Xlex_error(s sva_last)
  926. X    char        *s;
  927. X    sva_last_decl
  928. X{
  929. X    char        buffer[1024];
  930. X    va_list        ap;
  931. X
  932. X    sva_init(ap, s);
  933. X    assert(root);
  934. X    vsprintf(buffer, s, ap);
  935. X    va_end(ap);
  936. X    error("%s: %d: %s", root->l_name->str_text, root->l_line, buffer);
  937. X    if (++errcnt > 20)
  938. X        fatal("too many errors");
  939. X    option_set_errors();
  940. X}
  941. X
  942. X
  943. X/*
  944. X * NAME
  945. X *    lex_mode - change the mode of lexical analysis
  946. X *
  947. X * SYNOPSIS
  948. X *    int lex_mode(int n);
  949. X *
  950. X * DESCRIPTION
  951. X *    Lex_mode changes the mode of lexical analysis to the one given,
  952. X *    and returns the previous mode.
  953. X *
  954. X * CAVEAT
  955. X *    Use the #define's in lex.h.
  956. X */
  957. X
  958. Xint
  959. Xlex_mode(n)
  960. X    int        n;
  961. X{
  962. X    int        old;
  963. X
  964. X    old = mode;
  965. X    mode = n;
  966. X    return (old);
  967. X}
  968. X
  969. X
  970. X/*
  971. X * NAME
  972. X *    lex_trace - debug output
  973. X *
  974. X * SYNOPSIS
  975. X *    void lex_trace(char *s, ...);
  976. X *
  977. X * DESCRIPTION
  978. X *    The lex_trace function is used to format and output yyparse's trace
  979. X *    output.  The printf's in yyparse are #define'd into lex_trace calls.
  980. X *    Unfortunately yacc's designer did not take trace output redirection
  981. X *    into account, to this function is a little tedious.
  982. X *
  983. X * RETURNS
  984. X *    void
  985. X *
  986. X * CAVEAT
  987. X *    This function is only available when the DEBUG symbol is #define'd.
  988. X */
  989. X
  990. X#ifdef DEBUG
  991. X
  992. X/*VARARGS1*/
  993. Xvoid
  994. Xlex_trace(s sva_last)
  995. X    char        *s;
  996. X    sva_last_decl
  997. X{
  998. X    va_list        ap;
  999. X    static char    line[1024];
  1000. X    char        buffer[512];
  1001. X    char        *cp;
  1002. X
  1003. X    sva_init(ap, s);
  1004. X    vsprintf(buffer, s, ap);
  1005. X    va_end(ap);
  1006. X    strcat(line, buffer);
  1007. X    cp = line + strlen(line) - 1;
  1008. X    if (cp > line && *cp == '\n')
  1009. X    {
  1010. X        *cp = 0;
  1011. X        trace_printf
  1012. X        (
  1013. X            "%s: %d: %s\n",
  1014. X            root->l_name->str_text,
  1015. X            root->l_line,
  1016. X            line
  1017. X        );
  1018. X        line[0] = 0;
  1019. X    }
  1020. X}
  1021. X
  1022. X
  1023. Xstatic char *mode_repn _((int));
  1024. X
  1025. Xstatic char *
  1026. Xmode_repn(n)
  1027. X    int    n;
  1028. X{
  1029. X    static char *name[] =
  1030. X    {
  1031. X        "NORMAL",
  1032. X        "DATA",
  1033. X        "SQUOTE",
  1034. X        "DQUOTE",
  1035. X    };
  1036. X    static char buffer[12];
  1037. X
  1038. X    if (n >= 0 && n < SIZEOF(name))
  1039. X        return name[n];
  1040. X    sprintf(buffer, "%d", n);
  1041. X    return buffer;
  1042. X}
  1043. X
  1044. X#endif
  1045. X
  1046. X
  1047. X/*
  1048. X * NAME
  1049. X *    tokenize - lexical analyser
  1050. X *
  1051. X * SYNOPSIS
  1052. X *    int tokenize(void);
  1053. X *
  1054. X * DESCRIPTION
  1055. X *    The tokenize functionm is used to partition the input stream into
  1056. X *    discreet tokens. 
  1057. X *
  1058. X * CAVEAT
  1059. X *    Lex_open must have been called previously.
  1060. X */
  1061. X
  1062. Xstatic int tokenize _((void));
  1063. X
  1064. Xstatic int
  1065. Xtokenize()
  1066. X{
  1067. X    meta_ty        c;
  1068. X    int        tok;
  1069. X    static meta_ty    last;
  1070. X    static int    dataended;
  1071. X
  1072. X    trace(("tokenize()\n{\n"/*}*/));
  1073. X    if (dataended)
  1074. X    {
  1075. X        dataended = 0;
  1076. X        tok = DATAEND;
  1077. X        goto ret;
  1078. X    }
  1079. X
  1080. X    if (!catted && (last.m_flag & AFTER))
  1081. X    {
  1082. X        /*
  1083. X         * For parts of words in expressions which are abutted
  1084. X         * together, the user is implying catenation of the strings.
  1085. X         * This implied zero length token happens here.
  1086. X         */
  1087. X        meta(&c);
  1088. X        meta_undo(&c);
  1089. X        if (c.m_flag & BEFORE)
  1090. X        {
  1091. X            catted = 1;
  1092. X            tok = CATENATE;
  1093. X            goto ret;
  1094. X        }
  1095. X    }
  1096. X    else
  1097. X        catted = 0;
  1098. X
  1099. X    for (;;)
  1100. X    {
  1101. X        int     mark;
  1102. X
  1103. X        mark = 0;
  1104. X        meta(&c);
  1105. X        if (c.m_char == HASHLINE_ESCAPE)
  1106. X        {
  1107. X            state = 0;
  1108. X            last.m_flag = 0;
  1109. X            hashline();
  1110. X            state = 0;
  1111. X            last.m_flag = 0;
  1112. X            continue;
  1113. X        }
  1114. X        switch (c.m_type)
  1115. X        {
  1116. X        default:
  1117. X            fatal("illegal m_type %d (bug %d)", c.m_type, __LINE__);
  1118. X
  1119. X        case EOF:
  1120. X            tok = 0; /* by definition of yacc */
  1121. X            goto ret;
  1122. X
  1123. X        case NORMAL:
  1124. X        case SLOSHED:
  1125. X            {
  1126. X                int     sloshed;
  1127. X
  1128. X                sloshed = 0;
  1129. X                sa_open();
  1130. X                if (state == 0)
  1131. X                    mark = sa_mark();
  1132. X                for (;;)
  1133. X                {
  1134. X                    trace
  1135. X                    ((
  1136. X                            "%s: %d: state %d, mode %s;\n",
  1137. X                        root->l_name->str_text,
  1138. X                        root->l_line,
  1139. X                        state,
  1140. X                        mode_repn(mode)
  1141. X                    ));
  1142. X                    sa_char(c.m_char);
  1143. X                    if (c.m_type == SLOSHED)
  1144. X                    {
  1145. X                        sloshed = 1;
  1146. X                        switch (state)
  1147. X                        {
  1148. X                        default:
  1149. X                            state = 1;
  1150. X                            break;
  1151. X
  1152. X                        case 11:
  1153. X                        case 12:
  1154. X                            /* don't change state */
  1155. X                            break;
  1156. X                        }
  1157. X                    }
  1158. X                    else
  1159. X                    {
  1160. X                        switch (c.m_char)
  1161. X                        {
  1162. X                        default:
  1163. X                            switch (state)
  1164. X                            {
  1165. X                            default:
  1166. X                                state = 1;
  1167. X
  1168. X                            case 11:
  1169. X                            case 12:
  1170. X                                break;
  1171. X                            }
  1172. X                            break;
  1173. X
  1174. X                        case '\n':
  1175. X                            switch (state)
  1176. X                            {
  1177. X                            case 9:
  1178. X                            case 10:
  1179. X                                sa_goto(mark);
  1180. X                                parse_lval.lv_word = sa_close();
  1181. X                                state = 0;
  1182. X                                last.m_flag = 0; /* don't CAT after this */
  1183. X                                dataended = DATAEND;
  1184. X                                tok = WORD;
  1185. X                                goto ret;
  1186. X
  1187. X                            case 11:
  1188. X                            case 12:
  1189. X                                /* don't change state */
  1190. X                                lex_error("newline in quote");
  1191. X                                break;
  1192. X
  1193. X                            default:
  1194. X                                state = 0;
  1195. X                                mark = sa_mark();
  1196. X                                break;
  1197. X                            }
  1198. X                            break;
  1199. X
  1200. X                        case '\'':
  1201. X                            if (state != 12)
  1202. X                            {
  1203. X                                static        int        oldmode = LM_SQUOTE;
  1204. X
  1205. X                                oldmode = lex_mode(oldmode);
  1206. X                                sa_goto(sa_mark()-1);
  1207. X                                state = ((state == 11) ? 1 : 11);
  1208. X                                sloshed = 1;
  1209. X                            }
  1210. X                            break;
  1211. X
  1212. X                        case '"':
  1213. X                            if (state != 11)
  1214. X                            {
  1215. X                                static        int        oldmode = LM_DQUOTE;
  1216. X
  1217. X                                oldmode = lex_mode(oldmode);
  1218. X                                sa_goto(sa_mark()-1);
  1219. X                                state = ((state == 12) ? 1 : 12);
  1220. X                                sloshed = 1;
  1221. X                            }
  1222. X                            break;
  1223. X
  1224. X                        case ' ':
  1225. X                        case '\t':
  1226. X                            switch (state)
  1227. X                            {
  1228. X                            default:
  1229. X                                state = 1;
  1230. X                                break;
  1231. X
  1232. X                            case 0:
  1233. X                            case 2:
  1234. X                                state = 2;
  1235. X                                break;
  1236. X
  1237. X                            case 9:
  1238. X                            case 10:
  1239. X                                state = 10;
  1240. X                                break;
  1241. X
  1242. X                            case 11:
  1243. X                            case 12:
  1244. X                                break;
  1245. X                            }
  1246. X                            break;
  1247. X
  1248. X                        case 'a':
  1249. X                            switch (state)
  1250. X                            {
  1251. X                            default:
  1252. X                                state = 1;
  1253. X                                break;
  1254. X
  1255. X                            case 3:
  1256. X                            case 5:
  1257. X                                state++;
  1258. X                                break;
  1259. X
  1260. X                            case 11:
  1261. X                            case 12:
  1262. X                                break;
  1263. X                            }
  1264. X                            break;
  1265. X
  1266. X                        case 'd':
  1267. X                            switch (state)
  1268. X                            {
  1269. X                            default:
  1270. X                                state = 1;
  1271. X                                break;
  1272. X
  1273. X                            case 0:
  1274. X                            case 2:
  1275. X                                state = 3;
  1276. X                                break;
  1277. X
  1278. X                            case 8:
  1279. X                                state = 9;
  1280. X                                break;
  1281. X
  1282. X                            case 11:
  1283. X                            case 12:
  1284. X                                break;
  1285. X                            }
  1286. X                            break;
  1287. X
  1288. X                        case 'e':
  1289. X                            switch (state)
  1290. X                            {
  1291. X                            default:
  1292. X                                state = 1;
  1293. X                                break;
  1294. X
  1295. X                            case 6:
  1296. X                                state = 7;
  1297. X                                break;
  1298. X
  1299. X                            case 11:
  1300. X                            case 12:
  1301. X                                break;
  1302. X                            }
  1303. X                            break;
  1304. X
  1305. X                        case 'n':
  1306. X                            switch (state)
  1307. X                            {
  1308. X                            default:
  1309. X                                state = 1;
  1310. X                                break;
  1311. X
  1312. X                            case 7:
  1313. X                                state = 8;
  1314. X                                break;
  1315. X
  1316. X                            case 11:
  1317. X                            case 12:
  1318. X                                break;
  1319. X                            }
  1320. X                            break;
  1321. X
  1322. X                        case 't':
  1323. X                            switch (state)
  1324. X                            {
  1325. X                            default:
  1326. X                                state = 1;
  1327. X                                break;
  1328. X
  1329. X                            case 4:
  1330. X                                state = 5;
  1331. X                                break;
  1332. X
  1333. X                            case 11:
  1334. X                            case 12:
  1335. X                                break;
  1336. X                            }
  1337. X                            break;
  1338. X                        }
  1339. X                    }
  1340. X                    last = c;
  1341. X                    if (last.m_flag & SINGLE)
  1342. X                        break;
  1343. X                    meta(&c);
  1344. X                    if (c.m_flag & SINGLE)
  1345. X                    {
  1346. X                        meta_undo(&c);
  1347. X                        break;
  1348. X                    }
  1349. X                }
  1350. X                parse_lval.lv_word = sa_close();
  1351. X                if (sloshed)
  1352. X                    tok = WORD;
  1353. X                else
  1354. X                    tok = UNQUOTED_WORD;
  1355. X            }
  1356. X            goto ret;
  1357. X
  1358. X        case WHITE:
  1359. X            if (c.m_char == '\n')
  1360. X            {
  1361. X                state = 0;
  1362. X                tok = EOLN;
  1363. X                goto ret;
  1364. X            }
  1365. X            state = 1;
  1366. X            break;
  1367. X        }
  1368. X    }
  1369. X
  1370. X    ret:
  1371. X    trace(("return %d;\n", tok));
  1372. X    trace((/*{*/"}\n"));
  1373. X    return tok;
  1374. X}
  1375. X
  1376. X
  1377. X/*
  1378. X * NAME
  1379. X *    lex_cur_file - name current file
  1380. X *
  1381. X * SYNOPSIS
  1382. X *    string_ty *lex_cur_file(void);
  1383. X *
  1384. X * DESCRIPTION
  1385. X *    The lex_cur_file function is used to get the name of the current
  1386. X *    file being analyzed by lex.
  1387. X *
  1388. X * RETURNS
  1389. X *    string_ty* - pointer to string with name in it
  1390. X *
  1391. X * CAVEAT
  1392. X *    Does not take a copy, so don't use str_free()
  1393. X */
  1394. X
  1395. Xstring_ty *
  1396. Xlex_cur_file()
  1397. X{
  1398. X    assert(root);
  1399. X    return root->l_name;
  1400. X}
  1401. X
  1402. Xint
  1403. Xlex_cur_line()
  1404. X{
  1405. X    assert(root);
  1406. X    return root->l_line;
  1407. X}
  1408. X
  1409. X
  1410. X/*
  1411. X * NAME
  1412. X *    parse_lex - lexer for parse.y
  1413. X *
  1414. X * SYNOPSIS
  1415. X *    int parse_lex(void);
  1416. X *
  1417. X * DESCRIPTION
  1418. X *    The parse_lex function is used to turn the tokens generated
  1419. X *    by tokenize into parse.y tokens.
  1420. X *
  1421. X * RETURNS
  1422. X *    int - the token number
  1423. X *
  1424. X * CAVEAT
  1425. X *    Intended solely for use by the yacc-generated compiler
  1426. X */
  1427. X
  1428. Xint
  1429. Xparse_lex()
  1430. X{
  1431. X    int        tok;
  1432. X
  1433. X    trace(("parse_lex()\n{\n"/*}*/));
  1434. X    for (;;)
  1435. X    {
  1436. X        tok = tokenize();
  1437. X        if (!passing)
  1438. X        {
  1439. X            if (!tok)
  1440. X            {
  1441. X                lex_error("unterminated conditional");
  1442. X                break;
  1443. X            }
  1444. X            if (tok == WORD || tok == UNQUOTED_WORD)
  1445. X                str_free(parse_lval.lv_word);
  1446. X            continue;
  1447. X        }
  1448. X        switch (tok)
  1449. X        {
  1450. X        case EOLN:
  1451. X            continue;
  1452. X
  1453. X        case UNQUOTED_WORD:
  1454. X            if (id_search(parse_lval.lv_word, ID_CLASS_PARSE_KEYWORD, &tok))
  1455. X            {
  1456. X                str_free(parse_lval.lv_word);
  1457. X                parse_lval.lv_word = 0;
  1458. X                if (tok == COLON)
  1459. X                {
  1460. X                    parse_lval.lv_position.pos_name = str_copy(root->l_name);
  1461. X                    parse_lval.lv_position.pos_line = root->l_line;
  1462. X                }
  1463. X                if (tok == DATA)
  1464. X                {
  1465. X                    int    winged;
  1466. X                    meta_ty    last;
  1467. X                    meta_ty    c;
  1468. X    
  1469. X                    /*
  1470. X                     * This is a special.  Gobble the rest
  1471. X                     * of the line before he starts sucking
  1472. X                     * in the program data.
  1473. X                     */
  1474. X                    winged = 0;
  1475. X                    for (;;)
  1476. X                    {
  1477. X                        meta(&c);
  1478. X                        last = c;
  1479. X                        switch (c.m_type)
  1480. X                        {
  1481. X                        default:
  1482. X                            fatal("illegal m_type %d (bug %d)", c.m_type, __LINE__);
  1483. X    
  1484. X                        case EOF:
  1485. X                            illeof();
  1486. X    
  1487. X                        case NORMAL:
  1488. X                        case SLOSHED:
  1489. X                            if (!winged)
  1490. X                            {
  1491. X                                lex_error("the 'data' keyword must be the last on the line");
  1492. X                                winged = 1;
  1493. X                            }
  1494. X                            continue;
  1495. X    
  1496. X                        case WHITE:
  1497. X                            if (c.m_char != '\n')
  1498. X                                continue;
  1499. X                            state = 0;
  1500. X                            break;
  1501. X                        }
  1502. X                        break;
  1503. X                    }
  1504. X                    catted = 1;
  1505. X                }
  1506. X            }
  1507. X            else
  1508. X                tok = WORD;
  1509. X            break;
  1510. X        }
  1511. X        break;
  1512. X    }
  1513. X    trace(("return %d;\n", tok));
  1514. X    trace((/*{*/"}\n"));
  1515. X    return tok;
  1516. X}
  1517. X
  1518. X
  1519. X/*
  1520. X * NAME
  1521. X *    hashline_lex - lexer for hashline.y
  1522. X *
  1523. X * SYNOPSIS
  1524. X *    int hashline_lex(void);
  1525. X *
  1526. X * DESCRIPTION
  1527. X *    The hashline_lex function is used to turn the tokens generated
  1528. X *    by tokenize into hashline.y tokens.
  1529. X *
  1530. X * RETURNS
  1531. X *    int - the token number
  1532. X *
  1533. X * CAVEAT
  1534. X *    Intended solely for use by the yacc-generated compiler
  1535. X */
  1536. X
  1537. Xint
  1538. Xhashline_lex()
  1539. X{
  1540. X    int        tok;
  1541. X
  1542. X    trace(("hashline_lex()\n{\n"/*}*/));
  1543. X    tok = tokenize();
  1544. X    switch (tok)
  1545. X    {
  1546. X    case EOLN:
  1547. X        tok = 0;
  1548. X        break;
  1549. X
  1550. X    case UNQUOTED_WORD:
  1551. X        if (id_search(parse_lval.lv_word, ID_CLASS_HASH_KEYWORD, &tok))
  1552. X        {
  1553. X            str_free(parse_lval.lv_word);
  1554. X            parse_lval.lv_word = 0;
  1555. X        }
  1556. X        else
  1557. X            tok = WORD;
  1558. X        break;
  1559. X    }
  1560. X    memcpy(&hashline_lval, &parse_lval, sizeof(hashline_lval));
  1561. X    trace(("return %d;\n", tok));
  1562. X    trace((/*{*/"}\n"));
  1563. X    return tok;
  1564. X}
  1565. X
  1566. X
  1567. Xvoid
  1568. Xlex_passing(n)
  1569. X    int        n;
  1570. X{
  1571. X    passing = n;
  1572. X}
  1573. END_OF_FILE
  1574. if test 26740 -ne `wc -c <'cook/lex.c'`; then
  1575.     echo shar: \"'cook/lex.c'\" unpacked with wrong size!
  1576. fi
  1577. # end of 'cook/lex.c'
  1578. fi
  1579. if test -f 'cook/os.c' -a "${1}" != "-c" ; then 
  1580.   echo shar: Will not clobber existing file \"'cook/os.c'\"
  1581. else
  1582. echo shar: Extracting \"'cook/os.c'\" \(24336 characters\)
  1583. sed "s/^X//" >'cook/os.c' <<'END_OF_FILE'
  1584. X/*
  1585. X *    cook - file construction tool
  1586. X *    Copyright (C) 1991, 1992, 1993 Peter Miller.
  1587. X *    All rights reserved.
  1588. X *
  1589. X *    This program is free software; you can redistribute it and/or modify
  1590. X *    it under the terms of the GNU General Public License as published by
  1591. X *    the Free Software Foundation; either version 2 of the License, or
  1592. X *    (at your option) any later version.
  1593. X *
  1594. X *    This program is distributed in the hope that it will be useful,
  1595. X *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  1596. X *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1597. X *    GNU General Public License for more details.
  1598. X *
  1599. X *    You should have received a copy of the GNU General Public License
  1600. X *    along with this program; if not, write to the Free Software
  1601. X *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1602. X *
  1603. X * MANIFEST: functions to isolate operating system interface
  1604. X */
  1605. X
  1606. X#include <sys/types.h>
  1607. X#include <sys/stat.h>
  1608. X#include <sys/times.h>
  1609. X#include <sys/param.h>
  1610. X
  1611. X#include <stddef.h>
  1612. X#include <string.h>
  1613. X#include <stdlib.h>
  1614. X#include <limits.h>
  1615. X#include <errno.h>
  1616. X#include <stdio.h>
  1617. X#include <signal.h>
  1618. X#include <unistd.h>
  1619. X#include <utime.h>
  1620. X
  1621. X#include <conf.h>
  1622. X#include <error.h>
  1623. X#include <id.h>
  1624. X#include <mem.h>
  1625. X#include <option.h>
  1626. X#include <os.h>
  1627. X#include <trace.h>
  1628. X#include <word.h>
  1629. X
  1630. X#ifdef BSD
  1631. X#include <sys/time.h>
  1632. X#include <sys/resource.h>
  1633. X#endif
  1634. X
  1635. X
  1636. X/*
  1637. X * get rid if this real soon
  1638. X */
  1639. X#ifndef PATH_MAX
  1640. X# define PATH_MAX 1024
  1641. X#endif
  1642. X#ifndef NAME_MAX
  1643. X# ifdef BSD
  1644. X#  define NAME_MAX 255
  1645. X# else
  1646. X#  define NAME_MAX 14
  1647. X# endif
  1648. X#endif
  1649. X
  1650. X
  1651. X/*
  1652. X * NAME
  1653. X *    stat_cache - stat() with caching
  1654. X *
  1655. X * SYNOPSIS
  1656. X *    int stat_cache(string_ty *path, struct stat *result);
  1657. X *
  1658. X * DESCRIPTION
  1659. X *    The stat_cache function is used to perform the same as the stat()
  1660. X *    system function, but the results are cached to avoid too many probes
  1661. X *    into the file system.  Files which do not exist are indicated by
  1662. X *    filling the result structure with zeros.
  1663. X *
  1664. X * RETURNS
  1665. X *    int; -1 on error, 0 on success
  1666. X *
  1667. X * CAVEAT
  1668. X *    Errors, other than ENOENT, result in a fatal diagnostic.
  1669. X */
  1670. X
  1671. Xstatic int stat_cache _((string_ty *, struct stat *));
  1672. X
  1673. Xstatic int
  1674. Xstat_cache(path, result)
  1675. X    string_ty    *path;
  1676. X    struct stat    *result;
  1677. X{
  1678. X    if (id_search(path, ID_CLASS_STAT, result))
  1679. X        return 0;
  1680. X    if (stat(path->str_text, result))
  1681. X    {
  1682. X        switch (errno)
  1683. X        {
  1684. X        case ENOENT:
  1685. X        case ENOTDIR:
  1686. X            /*
  1687. X             * ENOENT occurs when a path element does not exist
  1688. X             * ENOTDIR occurs when a path element (except the last)
  1689. X             *        is not a directory.
  1690. X             * Either way, the file being "stat"ed does not exist.
  1691. X             */
  1692. X            break;
  1693. X
  1694. X        default:
  1695. X            nerror("stat(\"%s\")", path->str_text);
  1696. X            option_set_errors();
  1697. X            return -1;
  1698. X        }
  1699. X        memset(result, 0, sizeof(*result));
  1700. X    }
  1701. X    else
  1702. X    {
  1703. X        if (result->st_mtime < 1)
  1704. X            result->st_mtime = 1;
  1705. X    }
  1706. X    id_assign(path, ID_CLASS_STAT, result);
  1707. X    if (option_test(OPTION_TRACE))
  1708. X    {
  1709. X        if (!result->st_mtime)
  1710. X        {
  1711. X            error
  1712. X            (
  1713. X                "mtime(\"%s\") == ENOENT (trace)",
  1714. X                path->str_text
  1715. X            );
  1716. X        }
  1717. X        else
  1718. X        {
  1719. X            struct tm    *tm;
  1720. X
  1721. X            tm = localtime(&result->st_mtime);
  1722. X            error
  1723. X            (
  1724. X            "mtime(\"%s\") == %4d/%02d/%02d.%02d:%02d:%02d (trace)",
  1725. X                path->str_text,
  1726. X                1900 + tm->tm_year,
  1727. X                tm->tm_mon + 1,
  1728. X                tm->tm_mday,
  1729. X                tm->tm_hour,
  1730. X                tm->tm_min,
  1731. X                tm->tm_sec
  1732. X            );
  1733. X        }
  1734. X    }
  1735. X    return 0;
  1736. X}
  1737. X
  1738. X
  1739. X/*
  1740. X * NAME
  1741. X *    os_mtime - return the last-modified time of a file
  1742. X *
  1743. X * SYNOPSIS
  1744. X *    time_t os_mtime(string_ty *path);
  1745. X *
  1746. X * DESCRIPTION
  1747. X *    Os_mtime returns the time the named file was last modified.
  1748. X *    It returns -1L if the file does not exist.
  1749. X *
  1750. X * CAVEAT
  1751. X *    Assumes time will be the UNIX format.
  1752. X */
  1753. X
  1754. Xtime_t
  1755. Xos_mtime(path)
  1756. X    string_ty    *path;
  1757. X{
  1758. X    struct stat    buf;
  1759. X
  1760. X    if (stat_cache(path, &buf))
  1761. X        return -1;
  1762. X    return buf.st_mtime;
  1763. X}
  1764. X
  1765. X
  1766. X
  1767. X/*
  1768. X * NAME
  1769. X *    os_mtime_adjust - indicate change
  1770. X *
  1771. X * SYNOPSIS
  1772. X *    int os_mtime_adjust(string_ty *path);
  1773. X *
  1774. X * DESCRIPTION
  1775. X *    The os_mtime_adjust function is used to adjust the value in the stat
  1776. X *    cache to indicate that a recipe has constructed a file, and thus
  1777. X *    changed it last-modified time.  No change to the actual file system
  1778. X *    occurs.
  1779. X *
  1780. X * RETURNS
  1781. X *    int; -1 on error, 0 on success
  1782. X */
  1783. X
  1784. Xint
  1785. Xos_mtime_adjust(path)
  1786. X    string_ty    *path;
  1787. X{
  1788. X    struct stat    buf;
  1789. X    struct tm    *tm;
  1790. X
  1791. X    if (stat_cache(path, &buf))
  1792. X        return -1;
  1793. X    time(&buf.st_mtime);
  1794. X    if (buf.st_mtime < 1)
  1795. X        buf.st_mtime = 1;
  1796. X    id_assign(path, ID_CLASS_STAT, &buf);
  1797. X    if (option_test(OPTION_TRACE))
  1798. X    {
  1799. X        tm = localtime(&buf.st_mtime);
  1800. X        error
  1801. X        (
  1802. X            "mtime(\"%s\") = %4d/%02d/%02d.%02d:%02d:%02d (trace)",
  1803. X            path->str_text,
  1804. X            1900 + tm->tm_year,
  1805. X            tm->tm_mon + 1,
  1806. X            tm->tm_mday,
  1807. X            tm->tm_hour,
  1808. X            tm->tm_min,
  1809. X            tm->tm_sec
  1810. X        );
  1811. X    }
  1812. X    return 0;
  1813. X}
  1814. X
  1815. X
  1816. X/*
  1817. X * NAME
  1818. X *    os_clear_stat - invalidate cache
  1819. X *
  1820. X * SYNOPSIS
  1821. X *    int os_clear_stat(string_ty *path);
  1822. X *
  1823. X * DESCRIPTION
  1824. X *    The os_clear_stat function is used to invalidate the the stat
  1825. X *    cache to indicate that a recipe has constructed a file, and thus
  1826. X *    changed it last-modified time.  No change to the actual file system
  1827. X *    occurs.
  1828. X *
  1829. X * RETURNS
  1830. X *    int; 0 on success, -1 on error
  1831. X *
  1832. X * CAVEAT
  1833. X *    This is used in situations where the recipe changes a file not named
  1834. X *    in the targets of the recipe.  This usually occurs around mkdir, rm
  1835. X *    and mv commands, used in conjunction with the [exists] builtin function.
  1836. X */
  1837. X
  1838. Xint
  1839. Xos_clear_stat(path)
  1840. X    string_ty    *path;
  1841. X{
  1842. X    id_delete(path, ID_CLASS_STAT);
  1843. X    return 0;
  1844. X}
  1845. X
  1846. X
  1847. X/*
  1848. X * NAME
  1849. X *    os_touch - update the modify time of the file
  1850. X *
  1851. X * SYNOPSIS
  1852. X *    int os_touch(string_ty *path);
  1853. X *
  1854. X * DESCRIPTION
  1855. X *    Os_touch updates the last-modified time of the file to the present.
  1856. X *    If the named file does not exist, then nothing is done.
  1857. X *
  1858. X * RETURNS
  1859. X *    int; 0 on success, -1 on error
  1860. X */
  1861. X
  1862. Xint
  1863. Xos_touch(path)
  1864. X    string_ty    *path;
  1865. X{
  1866. X    struct stat    buf;
  1867. X    struct utimbuf    ut;
  1868. X
  1869. X    if (stat_cache(path, &buf))
  1870. X        return -1;
  1871. X    if (!buf.st_ino)
  1872. X        /* file does not exist */
  1873. X        return 0;
  1874. X    time(&ut.modtime);
  1875. X    if (ut.modtime < 0)
  1876. X        ut.modtime = 0;
  1877. X    ut.actime = buf.st_atime;
  1878. X    if (utime(path->str_text, &ut))
  1879. X    {
  1880. X        nerror("utime(\"%s\")", path->str_text);
  1881. X        option_set_errors();
  1882. X        return -1;
  1883. X    }
  1884. X    buf.st_mtime = ut.modtime;
  1885. X    id_assign(path, ID_CLASS_STAT, &buf);
  1886. X    return 0;
  1887. X}
  1888. X
  1889. X
  1890. X/*
  1891. X * NAME
  1892. X *    os_delete - delete a file
  1893. X *
  1894. X * SYNOPSIS
  1895. X *    int os_delete(string_ty *path);
  1896. X *
  1897. X * DESCRIPTION
  1898. X *    Os_delete deletes the named file.
  1899. X *    If it does not exist, no error is given.
  1900. X *
  1901. X * RETURNS
  1902. X *    int; -1 on error, 0 on success
  1903. X */
  1904. X
  1905. Xint
  1906. Xos_delete(path)
  1907. X    string_ty    *path;
  1908. X{
  1909. X    struct stat    buf;
  1910. X
  1911. X    if (unlink(path->str_text) && errno != ENOENT)
  1912. X    {
  1913. X        nerror("unlink(\"%s\")", path->str_text);
  1914. X        option_set_errors();
  1915. X        return -1;
  1916. X    }
  1917. X
  1918. X    /*
  1919. X     * if the knew about the existence of the file before we deleted
  1920. X     * it, then we will have to adjust the stat cache.
  1921. X     */
  1922. X    if (stat_cache(path, &buf))
  1923. X        return -1;
  1924. X    if (buf.st_ino)
  1925. X    {
  1926. X        memset(&buf, 0, sizeof(buf));
  1927. X        id_assign(path, ID_CLASS_STAT, &buf);
  1928. X    }
  1929. X    return 0;
  1930. X}
  1931. X
  1932. X
  1933. X/*
  1934. X * NAME
  1935. X *    signal_name - find it
  1936. X *
  1937. X * SYNOPSIS
  1938. X *    char *signal_name(int n);
  1939. X *
  1940. X * DESCRIPTION
  1941. X *    The signal_name function is used to find the name of a signal from its
  1942. X *    number.
  1943. X *
  1944. X * RETURNS
  1945. X *    char *: pointer to the signal name.
  1946. X *
  1947. X * CAVEAT
  1948. X *    The signal name may not be written on.  Subsequent calls may alter the
  1949. X *    area pointed to.
  1950. X */
  1951. X
  1952. Xchar *
  1953. Xsignal_name(n)
  1954. X    int        n;
  1955. X{
  1956. X    static char    buffer[16];
  1957. X
  1958. X    switch (n)
  1959. X    {
  1960. X#ifdef SIGHUP
  1961. X    case SIGHUP:
  1962. X        return "hang up [SIGHUP]";
  1963. X#endif /* SIGHUP */
  1964. X
  1965. X#ifdef SIGINT
  1966. X    case SIGINT:
  1967. X        return "user interrupt [SIGINT]";
  1968. X#endif /* SIGINT */
  1969. X
  1970. X#ifdef SIGQUIT
  1971. X    case SIGQUIT:
  1972. X        return "user quit [SIGQUIT]";
  1973. X#endif /* SIGQUIT */
  1974. X
  1975. X#ifdef SIGILL
  1976. X    case SIGILL:
  1977. X        return "illegal instruction [SIGILL]";
  1978. X#endif /* SIGILL */
  1979. X
  1980. X#ifdef SIGTRAP
  1981. X    case SIGTRAP:
  1982. X        return "trace trap [SIGTRAP]";
  1983. X#endif /* SIGTRAP */
  1984. X
  1985. X#ifdef SIGIOT
  1986. X    case SIGIOT:
  1987. X        return "abort [SIGIOT]";
  1988. X#endif /* SIGIOT */
  1989. X
  1990. X#ifdef SIGEMT
  1991. X    case SIGEMT:
  1992. X        return "EMT instruction [SIGEMT]";
  1993. X#endif /* SIGEMT */
  1994. X
  1995. X#ifdef SIGFPE
  1996. X    case SIGFPE:
  1997. X        return "floating point exception [SIGFPE]";
  1998. X#endif /* SIGFPE */
  1999. X
  2000. X#ifdef SIGKILL
  2001. X    case SIGKILL:
  2002. X        return "kill [SIGKILL]";
  2003. X#endif /* SIGKILL */
  2004. X
  2005. X#ifdef SIGBUS
  2006. X    case SIGBUS:
  2007. X        return "bus error [SIGBUS]";
  2008. X#endif /* SIGBUS */
  2009. X
  2010. X#ifdef SIGSEGV
  2011. X    case SIGSEGV:
  2012. X        return "segmentation violation [SIGSEGV]";
  2013. X#endif /* SIGSEGV */
  2014. X
  2015. X#ifdef SIGSYS
  2016. X    case SIGSYS:
  2017. X        return "bad argument to system call [SIGSYS]";
  2018. X#endif /* SIGSYS */
  2019. X
  2020. X#ifdef SIGPIPE
  2021. X    case SIGPIPE:
  2022. X        return "write on a pipe with no one to read it [SIGPIPE]";
  2023. X#endif /* SIGPIPE */
  2024. X
  2025. X#ifdef SIGALRM
  2026. X    case SIGALRM:
  2027. X        return "alarm clock [SIGALRM]";
  2028. X#endif /* SIGALRM */
  2029. X
  2030. X#ifdef SIGTERM
  2031. X    case SIGTERM:
  2032. X        return "software termination [SIGTERM]";
  2033. X#endif /* SIGTERM */
  2034. X
  2035. X#ifdef SIGUSR1
  2036. X    case SIGUSR1:
  2037. X        return "user defined signal one [SIGUSR1]";
  2038. X#endif /* SIGUSR1 */
  2039. X
  2040. X#ifdef SIGUSR2
  2041. X    case SIGUSR2:
  2042. X        return "user defined signal two [SIGUSR2]";
  2043. X#endif /* SIGUSR2 */
  2044. X
  2045. X#ifdef SIGCLD
  2046. X    case SIGCLD:
  2047. X        return "death of child [SIGCLD]";
  2048. X#endif /* SIGCLD */
  2049. X
  2050. X#ifdef SIGPWR
  2051. X    case SIGPWR:
  2052. X        return "power failure [SIGPWR]";
  2053. X#endif /* SIGPWR */
  2054. X
  2055. X    default:
  2056. X        sprintf(buffer, "signal %d", n);
  2057. X        return buffer;
  2058. X    }
  2059. X}
  2060. X
  2061. X
  2062. X/*
  2063. X * NAME
  2064. X *    exit_status - pretty print
  2065. X *
  2066. X * SYNOPSIS
  2067. X *    int exit_status(char *cmd, int status);
  2068. X *
  2069. X * DESCRIPTION
  2070. X *    The exit_status function is used to pretty print the meaning of the
  2071. X *    exit status of the given command.  No output is generated for normal
  2072. X *    (0) termination.
  2073. X *
  2074. X * RETURNS
  2075. X *    int: zero if the command succeeded, 1 if it failed.
  2076. X *
  2077. X * CAVEAT
  2078. X *    This function should be static, but func_collect (builtin.c) uses it.
  2079. X */
  2080. X
  2081. Xint
  2082. Xexit_status(cmd, status)
  2083. X    char        *cmd;
  2084. X    int        status;
  2085. X{
  2086. X    int        a, b, c;
  2087. X
  2088. X    a = (status >> 8) & 0xFF;
  2089. X    b = (status >> 7) & 1;
  2090. X    c = status & 0x7F;
  2091. X    switch (c)
  2092. X    {
  2093. X    case 0x7F:
  2094. X        /*
  2095. X         * process was stopped,
  2096. X         * since we didn't do it, treat it as an error
  2097. X         */
  2098. X        error("%s: stopped", cmd);
  2099. X        return 1;
  2100. X
  2101. X    case 0:
  2102. X        /* normal termination */
  2103. X        if (a)
  2104. X        {
  2105. X            error("%s: exit status: %d", cmd, a);
  2106. X            return 1;
  2107. X        }
  2108. X        return 0;
  2109. X
  2110. X    default:
  2111. X        /*
  2112. X         * process dies from unhandled condition
  2113. X         */
  2114. X        error
  2115. X        (
  2116. X            "%s: terminated by %s%s",
  2117. X            cmd,
  2118. X            signal_name(c),
  2119. X            (b ? " (core dumped)" : "")
  2120. X        );
  2121. X        return 1;
  2122. X    }
  2123. X}
  2124. X
  2125. X
  2126. X/*
  2127. X * NAME
  2128. X *    execute - do a command
  2129. X *
  2130. X * SYNOPSIS
  2131. X *    int execute(wlist *cmd, int fd);
  2132. X *
  2133. X * DESCRIPTION
  2134. X *    The execute function is used to execute the command in the word list.
  2135. X *    If the file descriptor is >= 0, it indicates a file to use as stdin to
  2136. X *    the command.
  2137. X *
  2138. X * RETURNS
  2139. X *    int: zero if the commands succeeds, nonzero if it fails.
  2140. X *
  2141. X * CAVEAT
  2142. X */
  2143. X
  2144. Xstatic int execute _((wlist *, int));
  2145. X
  2146. Xstatic int
  2147. Xexecute(cmd, fd)
  2148. X    wlist        *cmd;
  2149. X    int        fd;
  2150. X{
  2151. X    int        child;
  2152. X    int        pid;
  2153. X    int        status;
  2154. X    static char    **argv;
  2155. X    static size_t    argvlen;
  2156. X    int        j;
  2157. X
  2158. X    if (!argv)
  2159. X    {
  2160. X        argvlen = cmd->wl_nwords + 1;
  2161. X        argv = (char **)mem_alloc(argvlen * sizeof(char*));
  2162. X    }
  2163. X    else
  2164. X    {
  2165. X        if (argvlen < cmd->wl_nwords + 1)
  2166. X        {
  2167. X            argvlen = cmd->wl_nwords + 1;
  2168. X            mem_change_size((char **)&argv, argvlen * sizeof(char*));
  2169. X        }
  2170. X    }
  2171. X    for (j = 0; j < cmd->wl_nwords; ++j)
  2172. X        argv[j] = cmd->wl_word[j]->str_text;
  2173. X    argv[cmd->wl_nwords] = 0;
  2174. X    switch (child = fork())
  2175. X    {
  2176. X    case -1:
  2177. X        nerror("fork()");
  2178. X        return -1;
  2179. X
  2180. X    case 0:
  2181. X        if (fd >= 0)
  2182. X        {
  2183. X            if (close(0) && errno != EBADF)
  2184. X                nfatal("close(0)");
  2185. X            if (dup(fd) < 0)
  2186. X                nfatal("dup()");
  2187. X        }
  2188. X        if (argv[0][0] == '/')
  2189. X            execv(argv[0], argv);
  2190. X        else
  2191. X            execvp(argv[0], argv);
  2192. X        nfatal("exec(\"%s\")", argv[0]);
  2193. X
  2194. X    default:
  2195. X        for (;;)
  2196. X        {
  2197. X            pid = wait(&status);
  2198. X            if (pid == child)
  2199. X                return exit_status(argv[0], status);
  2200. X            if (pid < 0 && errno != EINTR)
  2201. X            {
  2202. X                nerror("wait()");
  2203. X                option_set_errors();
  2204. X                return -1;
  2205. X            }
  2206. X        }
  2207. X    }
  2208. X}
  2209. X
  2210. X
  2211. X/*
  2212. X * NAME
  2213. X *    os_execute - execute a command
  2214. X *
  2215. X * SYNOPSIS
  2216. X *    int os_execute(wlist *args, string_ty *input);
  2217. X *
  2218. X * DESCRIPTION
  2219. X *    Os_execute performs the given command.
  2220. X *    If the command succeeds 0 is returned.
  2221. X *    If the command fails a diagnostic message is given
  2222. X *    and 1 is returned.
  2223. X */
  2224. X
  2225. Xint
  2226. Xos_execute(args, input)
  2227. X    wlist        *args;
  2228. X    string_ty    *input;
  2229. X{
  2230. X    int        j;
  2231. X    FILE        *fp;
  2232. X    char        iname[L_tmpnam];
  2233. X    int        retval;
  2234. X
  2235. X    assert(args);
  2236. X    assert(args->wl_nwords > 0);
  2237. X
  2238. X    fp = 0;
  2239. X    if (input)
  2240. X    {
  2241. X        /*
  2242. X         * He has given a string to be used as input to the command,
  2243. X         * so write it out to a file, and then redirect the input.
  2244. X         */
  2245. X        tmpnam(iname);
  2246. X        fp = fopen(iname, "w");
  2247. X        if (!fp)
  2248. X        {
  2249. X            nerror("create %s", iname);
  2250. X            exec_fails:
  2251. X            option_set_errors();
  2252. X            retval = -1;
  2253. X            goto ret;
  2254. X        }
  2255. X        if (unlink(iname))
  2256. X        {
  2257. X            nerror("unlink(\"%s\")", iname);
  2258. X            goto exec_fails;
  2259. X        }
  2260. X        fputs(input->str_text, fp);
  2261. X        if (ferror(fp) || fseek(fp, 0L, 0))
  2262. X        {
  2263. X            nerror("write %s", iname);
  2264. X            goto exec_fails;
  2265. X        }
  2266. X    }
  2267. X
  2268. X    for (j = 1; j < args->wl_nwords; j++)
  2269. X    {
  2270. X        char    *s;
  2271. X
  2272. X        s = args->wl_word[j]->str_text;
  2273. X        while (*s)
  2274. X        {
  2275. X            if (strchr("#|=^();&<>*?[]:$`'\"\\\n", *s))
  2276. X            {
  2277. X                string_ty    *str;
  2278. X                wlist        newcmd;
  2279. X                char        *cp;
  2280. X
  2281. X                cp = getenv("SHELL");
  2282. X                if (!cp || !*cp)
  2283. X                    cp = CONF_SHELL;
  2284. X                wl_zero(&newcmd);
  2285. X                str = str_from_c(cp);
  2286. X                wl_append(&newcmd, str);
  2287. X                str_free(str);
  2288. X                if (option_test(OPTION_ERROK))
  2289. X                    str = str_from_c("-c");
  2290. X                else
  2291. X                    str = str_from_c("-ce");
  2292. X                wl_append(&newcmd, str);
  2293. X                str_free(str);
  2294. X                str = wl2str(args, 0, 32767);
  2295. X                wl_append(&newcmd, str);
  2296. X                str_free(str);
  2297. X                retval = execute(&newcmd, input ? fileno(fp) : -1);
  2298. X                wl_free(&newcmd);
  2299. X                if (input)
  2300. X                    fclose(fp);
  2301. X                return retval;
  2302. X            }
  2303. X            ++s;
  2304. X        }
  2305. X    }
  2306. X    retval = execute(args, input ? fileno(fp) : -1);
  2307. X    if (input)
  2308. X        fclose(fp);
  2309. Xret:
  2310. X    return retval;
  2311. X}
  2312. X
  2313. X
  2314. X/*
  2315. X * NAME
  2316. X *    os_exists - tests for the existence of a file
  2317. X *
  2318. X * SYNOPSIS
  2319. X *    int os_exists(string_ty *path);
  2320. X *
  2321. X * DESCRIPTION
  2322. X *    The os_exists function is used to determine the existence of a file.
  2323. X *
  2324. X * RETURNS
  2325. X *    int; 1 if the file exists, 0 if it does not.  -1 on error
  2326. X */
  2327. X
  2328. Xint
  2329. Xos_exists(path)
  2330. X    string_ty    *path;
  2331. X{
  2332. X    struct stat    buf;
  2333. X
  2334. X    if (stat_cache(path, &buf))
  2335. X        return -1;
  2336. X    return (buf.st_ino != 0);
  2337. X}
  2338. X
  2339. X
  2340. X/*
  2341. X * NAME
  2342. X *    os_accdir - return the directory path of the users account
  2343. X *
  2344. X * SYNOPSIS
  2345. X *    string_ty *os_accdir(void);
  2346. X *
  2347. X * DESCRIPTION
  2348. X *    The full pathname of the user's account is returned.
  2349. X *    The string will have been dynamically allocated.
  2350. X *
  2351. X * RETURNS
  2352. X *    A pointer to a string in dynamic memory is returned.
  2353. X *    A null pointer is returned on error.
  2354. X *
  2355. X * CAVEAT
  2356. X *    Use str_free() when you are done with the value returned.
  2357. X */
  2358. X
  2359. Xstring_ty *
  2360. Xos_accdir()
  2361. X{
  2362. X    static char    home[] = "HOME";
  2363. X    static string_ty    *s;
  2364. X
  2365. X    if (!s)
  2366. X    {
  2367. X        char        *cp;
  2368. X
  2369. X        cp = getenv(home);
  2370. X        if (!cp)
  2371. X        {
  2372. X            error("%s: environment variable not defined", home);
  2373. X            option_set_errors();
  2374. X            return 0;
  2375. X        }
  2376. X        s = str_from_c(cp);
  2377. X    }
  2378. X    return str_copy(s);
  2379. X}
  2380. X
  2381. X
  2382. X/*
  2383. X * NAME
  2384. X *    os_curdir - full current directory path
  2385. X *
  2386. X * SYNOPSIS
  2387. X *    string_ty *os_curdir(void);
  2388. X *
  2389. X * DESCRIPTION
  2390. X *    Os_curdir is used to determine the full pathname
  2391. X *    of the current directory.
  2392. X *
  2393. X * RETURNS
  2394. X *    A pointer to a string in dynamic memory is returned.
  2395. X *    A null pointer is returned on error.
  2396. X *
  2397. X * CAVEAT
  2398. X *    Use str_free() when you are done with the value returned.
  2399. X */
  2400. X
  2401. Xstring_ty *
  2402. Xos_curdir()
  2403. X{
  2404. X    static string_ty    *s;
  2405. X
  2406. X    if (!s)
  2407. X    {
  2408. X        char        buffer[PATH_MAX + 1];
  2409. X
  2410. X        if (!getcwd(buffer, sizeof(buffer)))
  2411. X        {
  2412. X            nerror("getcwd");
  2413. X            option_set_errors();
  2414. X            return 0;
  2415. X        }
  2416. X        s = str_from_c(buffer);
  2417. X    }
  2418. X    return str_copy(s);
  2419. X}
  2420. X
  2421. X
  2422. X/*
  2423. X * NAME
  2424. X *    os_pathname - determine full file name
  2425. X *
  2426. X * SYNOPSIS
  2427. X *    string_ty *os_pathname(string_ty *path);
  2428. X *
  2429. X * DESCRIPTION
  2430. X *    Os_pathname is used to determine the full path name
  2431. X *    of a partial path given.
  2432. X *
  2433. X * RETURNS
  2434. X *    pointer to dynamically allocated string.
  2435. X *
  2436. X * CAVEAT
  2437. X *    Use str_free() when you are done with the value returned.
  2438. X */
  2439. X
  2440. Xstring_ty *
  2441. Xos_pathname(path)
  2442. X    string_ty    *path;
  2443. X{
  2444. X    static char    *tmp;
  2445. X    static size_t    tmplen;
  2446. X    static size_t    ipos;
  2447. X    static size_t    opos;
  2448. X    int        c;
  2449. X    int        found;
  2450. X#ifdef S_IFLNK
  2451. X    char        link[2000];
  2452. X    int        nbytes;
  2453. X    wlist        loop;
  2454. X    string_ty    *s;
  2455. X#endif
  2456. X
  2457. X    /*
  2458. X     * Change relative pathnames to absolute
  2459. X     */
  2460. X    trace(("os_pathname(path = %08lX)\n{\n"/*}*/, path));
  2461. X    trace_string(path->str_text);
  2462. X    if (path->str_text[0] != '/')
  2463. X    {
  2464. X        string_ty    *cwd;
  2465. X
  2466. X        cwd = os_curdir();
  2467. X        assert(cwd);
  2468. X        path = str_format("%S/%S", cwd, path);
  2469. X        str_free(cwd);
  2470. X    }
  2471. X    else
  2472. X        path = str_copy(path);
  2473. X    if (!tmp)
  2474. X    {
  2475. X        tmplen = 200;
  2476. X        tmp = mem_alloc(tmplen);
  2477. X    }
  2478. X
  2479. X    /*
  2480. X     * Take kinks out of the pathname
  2481. X     */
  2482. X    ipos = 0;
  2483. X    opos = 0;
  2484. X    found = 0;
  2485. X#ifdef S_IFLNK
  2486. X    wl_zero(&loop);
  2487. X#endif
  2488. X    while (!found)
  2489. X    {
  2490. X        /*
  2491. X         * get the next character
  2492. X         */
  2493. X        c = path->str_text[ipos];
  2494. X        if (c)
  2495. X            ipos++;
  2496. X        else
  2497. X        {
  2498. X            found = 1;
  2499. X            c = '/';
  2500. X        }
  2501. X
  2502. X        /*
  2503. X         * remember the normal characters
  2504. X         * until get to slash
  2505. X         */
  2506. X        if (c != '/')
  2507. X            goto remember;
  2508. X
  2509. X        /*
  2510. X         * leave root alone
  2511. X         */
  2512. X        if (!opos)
  2513. X            goto remember;
  2514. X
  2515. X        /*
  2516. X         * "/.." -> "/"
  2517. X         */
  2518. X        if (opos == 3 && tmp[1] == '.' && tmp[2] == '.')
  2519. X        {
  2520. X            opos = 1;
  2521. X            continue;
  2522. X        }
  2523. X
  2524. X        /*
  2525. X         * "a//" -> "a/"
  2526. X         */
  2527. X        if (tmp[opos - 1] == '/')
  2528. X            continue;
  2529. X
  2530. X        /*
  2531. X         * "a/./" -> "a/"
  2532. X         */
  2533. X        if (opos >= 2 && tmp[opos - 1] == '.' && tmp[opos - 2] == '/')
  2534. X        {
  2535. X            opos--;
  2536. X            continue;
  2537. X        }
  2538. X
  2539. X        /*
  2540. X         * "a/b/../" -> "a/"
  2541. X         */
  2542. X        if
  2543. X        (
  2544. X            opos > 3
  2545. X        &&
  2546. X            tmp[opos - 1] == '.'
  2547. X        &&
  2548. X            tmp[opos - 2] == '.'
  2549. X        &&
  2550. X            tmp[opos - 3] == '/'
  2551. X        )
  2552. X        {
  2553. X            opos -= 4;
  2554. X            assert(opos > 0);
  2555. X            while (tmp[opos - 1] != '/')
  2556. X                opos--;
  2557. X            continue;
  2558. X        }
  2559. X
  2560. X        /*
  2561. X         * see if the path so far is a symbolic link
  2562. X         */
  2563. X#ifdef S_IFLNK
  2564. X        s = str_n_from_c(tmp, opos);
  2565. X        if (wl_member(&loop, s))
  2566. X        {
  2567. X            fatal
  2568. X            (
  2569. X                "symbolic link loop \"%s\" detected",
  2570. X                s->str_text
  2571. X            );
  2572. X        }
  2573. X        nbytes = readlink(s->str_text, link, sizeof(link) - 1);
  2574. X        if (nbytes < 0)
  2575. X        {
  2576. X            /*
  2577. X             * probably not a symbolic link
  2578. X             */
  2579. X            if (errno != EINVAL && errno != ENOENT)
  2580. X                nfatal("readlink(\"%s\")", s->str_text);
  2581. X            not_a_symlink:
  2582. X            str_free(s);
  2583. X        }
  2584. X        else
  2585. X        {
  2586. X            string_ty    *newpath;
  2587. X
  2588. X            if (nbytes == 0)
  2589. X            {
  2590. X                fatal
  2591. X                (
  2592. X                    "readlink(\"%s\") returned \"\"",
  2593. X                    s->str_text
  2594. X                );
  2595. X            }
  2596. X            link[nbytes] = 0;
  2597. X
  2598. X            /*
  2599. X             * ignore auto-mounter temporary mount links,
  2600. X             * they will change with each mount.
  2601. X             */
  2602. X            if (!strncmp(link, "/tmp_mnt/", 9))
  2603. X                goto not_a_symlink;
  2604. X
  2605. X            wl_append(&loop, s);
  2606. X            str_free(s);
  2607. X            if (link[0] == '/')
  2608. X                tmp[1] = 0;
  2609. X            else
  2610. X            {
  2611. X                while (tmp[opos - 1] != '/')
  2612. X                    opos--;
  2613. X                tmp[opos] = 0;
  2614. X            }
  2615. X            newpath =
  2616. X                str_format
  2617. X                (
  2618. X                    "%s/%s/%s",
  2619. X                    tmp,
  2620. X                    link,
  2621. X                    path->str_text + ipos
  2622. X                );
  2623. X            str_free(path);
  2624. X            path = newpath;
  2625. X            ipos = 0;
  2626. X            opos = 0;
  2627. X            found = 0;
  2628. X            continue;
  2629. X        }
  2630. X#endif
  2631. X    
  2632. X        /*
  2633. X         * keep the slash
  2634. X         */
  2635. X        remember:
  2636. X        if (opos >= tmplen)
  2637. X        {
  2638. X            tmplen += 100;
  2639. X            mem_change_size(&tmp, tmplen);
  2640. X        }
  2641. X        tmp[opos++] = c;
  2642. X    }
  2643. X#ifdef S_IFLNK
  2644. X    wl_free(&loop);
  2645. X#endif
  2646. X    str_free(path);
  2647. X    assert(opos >= 1);
  2648. X    assert(tmp[0] == '/');
  2649. X    assert(tmp[opos - 1] == '/');
  2650. X    if (opos >= 2)
  2651. X        opos--;
  2652. X    path = str_n_from_c(tmp, opos);
  2653. X    trace_string(path->str_text);
  2654. X    trace((/*{*/"}\n"));
  2655. X    return path;
  2656. X}
  2657. X
  2658. X
  2659. X/*
  2660. X * NAME
  2661. X *    os_entryname - take path apart
  2662. X *
  2663. X * SYNOPSIS
  2664. X *    string_ty *os_entryname(string_ty *path);
  2665. X *
  2666. X * DESCRIPTION
  2667. X *    Os_entryname is used to extract the entry part
  2668. X *    from a pathname.
  2669. X *
  2670. X * RETURNS
  2671. X *    pointer to dynamically allocated string.
  2672. X *
  2673. X * CAVEAT
  2674. X *    Use str_free() when you are done with the return value.
  2675. X */
  2676. X
  2677. Xstring_ty *
  2678. Xos_entryname(path)
  2679. X    string_ty    *path;
  2680. X{
  2681. X    char        *cp;
  2682. X
  2683. X    trace(("os_entryname(path = %08lX) entry", path));
  2684. X    trace_string(path->str_text);
  2685. X    cp = strrchr(path->str_text, '/');
  2686. X    if (cp)
  2687. X        path = str_from_c(cp + 1);
  2688. X    else
  2689. X        path = str_copy(path);
  2690. X    trace_string(path->str_text);
  2691. X    trace(("return %08lX;\n", path));
  2692. X    trace((/*{*/"}\n"));
  2693. X    return path;
  2694. X}
  2695. X
  2696. X
  2697. X/*
  2698. X * NAME
  2699. X *    os_dirname - take path apart
  2700. X *
  2701. X * SYNOPSIS
  2702. X *    string_ty *os_dirname(string_ty *path);
  2703. X *
  2704. X * DESCRIPTION
  2705. X *    Os_dirname is used to extract the directory part
  2706. X *    of a pathname.
  2707. X *
  2708. X * RETURNS
  2709. X *    pointer to dynamically allocated string.
  2710. X *    A null pointer is returned on error.
  2711. X *
  2712. X * CAVEAT
  2713. X *    Use str_free() when you are done with the value returned.
  2714. X */
  2715. X
  2716. Xstring_ty *
  2717. Xos_dirname(path)
  2718. X    string_ty    *path;
  2719. X{
  2720. X    char        *cp;
  2721. X
  2722. X    trace(("os_dirname(path = %08lX)\n{\n"/*}*/, path));
  2723. X    trace_string(path->str_text);
  2724. X    cp = strrchr(path->str_text, '/');
  2725. X    if (cp)
  2726. X    {
  2727. X        if (cp > path->str_text)
  2728. X            path = str_n_from_c(path->str_text, cp - path->str_text);
  2729. X        else
  2730. X            path = str_from_c("/");
  2731. X    }
  2732. X    else
  2733. X        path = os_curdir();
  2734. X    trace_string(path->str_text);
  2735. X    trace(("return %08lX;\n", path));
  2736. X    trace((/*{*/"}\n"));
  2737. X    return path;
  2738. X}
  2739. X
  2740. X
  2741. X/*
  2742. X * NAME
  2743. X *    os_meter_grab - get metering snapshot
  2744. X *
  2745. X * SYNOPSIS
  2746. X *    void os_meter_grab(grab*);
  2747. X *
  2748. X * DESCRIPTION
  2749. X *    The os_meter_gram function is used to take a snapshot of metering
  2750. X *    information.
  2751. X *
  2752. X * RETURNS
  2753. X *    void
  2754. X */
  2755. X
  2756. Xtypedef struct grab grab;
  2757. Xstruct grab
  2758. X{
  2759. X    double    g_elapsed;
  2760. X    double    g_cpu;
  2761. X    double    g_io;
  2762. X};
  2763. X
  2764. Xstatic void os_meter_grab _((grab *));
  2765. X
  2766. Xstatic void
  2767. Xos_meter_grab(gp)
  2768. X    grab        *gp;
  2769. X{
  2770. X#ifdef BSD
  2771. X    struct rusage    ru;
  2772. X    struct timeval    tv;
  2773. X    struct timezone    tz;
  2774. X
  2775. X    int getrusage _((int, struct rusage *));
  2776. X    int gettimeofday _((struct timeval *, struct timezone *));
  2777. X
  2778. X    if (getrusage(RUSAGE_CHILDREN, &ru))
  2779. X        nfatal("getrusage");
  2780. X    if (gettimeofday(&tv, &tz))
  2781. X        nfatal("gettimeofday");
  2782. X    gp->g_cpu = ru.ru_utime.tv_sec + ru.ru_utime.tv_usec * 1.0e-6;
  2783. X    gp->g_io = ru.ru_stime.tv_sec + ru.ru_stime.tv_usec * 1.0e-6;
  2784. X    gp->g_elapsed = tv.tv_sec + tv.tv_usec * 1.0e-6;
  2785. X#else
  2786. X    struct tms    buffer;
  2787. X    time_t        n;
  2788. X
  2789. X    n = times(&buffer);
  2790. X    gp->g_elapsed = n / (double)HZ;
  2791. X    gp->g_cpu = buffer.tms_cutime / (double)HZ;
  2792. X    gp->g_io = buffer.tms_cstime / (double)HZ;
  2793. X#endif
  2794. X}
  2795. X
  2796. X
  2797. X/*
  2798. X * NAME
  2799. X *    os_meter_ptime - print timing info
  2800. X *
  2801. X * SYNOPSIS
  2802. X *    void os_meter_ptime(double t, char *s, double elapsed);
  2803. X *
  2804. X * DESCRIPTION
  2805. X *    The os_meter_ptime function is used to print e representation of the
  2806. X *    time, in seconds, given in the `t' argument.  If `elapsed' is >0, it is
  2807. X *    the elapsed time taken, for percentage figures.  The `s' argument is a
  2808. X *    title string.
  2809. X *
  2810. X * RETURNS
  2811. X *    void
  2812. X */
  2813. X
  2814. Xstatic void os_meter_ptime _((double, char *, double));
  2815. X
  2816. Xstatic void
  2817. Xos_meter_ptime(t,s,e)
  2818. X    double    t;
  2819. X    char    *s;
  2820. X    double    e;
  2821. X{
  2822. X    char    buffer[32];
  2823. X    char    temp[32];
  2824. X    long    hour, min, sec, frac;
  2825. X
  2826. X    frac = t * 1000 + 0.5;
  2827. X    sec = frac / 1000;
  2828. X    frac %= 1000;
  2829. X    min = sec / 60;
  2830. X    sec %= 60;
  2831. X    hour = min / 60;
  2832. X    min %= 60;
  2833. X    if (e > 0.0)
  2834. X    {
  2835. X        sprintf(temp, "(%.2f%%)", 100. * t / e);
  2836. X        sprintf(buffer, "%-4s%9s", s, temp);
  2837. X        s = buffer;
  2838. X    }
  2839. X    fprintf(stderr, "%2ld:%02ld:%02ld.%03ld %s\n", hour, min, sec, frac, s);
  2840. X}
  2841. X
  2842. X
  2843. X/*
  2844. X * NAME
  2845. X *    os_meter_begin - start metering interval
  2846. X *
  2847. X * SYNOPSIS
  2848. X *    void os_meter_begin(void);
  2849. X *
  2850. X * DESCRIPTION
  2851. X *    The os_meter_begin function is used to start a metring interval.
  2852. X *
  2853. X * RETURNS
  2854. X *    void
  2855. X */
  2856. X
  2857. Xstatic    grab    os_meter_start;
  2858. X
  2859. Xvoid
  2860. Xos_meter_begin()
  2861. X{
  2862. X    os_meter_grab(&os_meter_start);
  2863. X}
  2864. X
  2865. X
  2866. X/*
  2867. X * NAME
  2868. X *    os_meter_end - end a metering interval
  2869. X *
  2870. X * SYNOPSIS
  2871. X *    void os_meter_end(void);
  2872. X *
  2873. X * DESCRIPTION
  2874. X *    The os_meter_end function is used to end a metering interval and print
  2875. X *    the metered information.
  2876. X *
  2877. X * RETURNS
  2878. X *    void
  2879. X */
  2880. X
  2881. Xvoid
  2882. Xos_meter_end()
  2883. X{
  2884. X    grab    end;
  2885. X    double    elapsed;
  2886. X    double    cpu;
  2887. X    double    io;
  2888. X
  2889. X    os_meter_grab(&end);
  2890. X
  2891. X    elapsed = end.g_elapsed - os_meter_start.g_elapsed;
  2892. X    os_meter_ptime(elapsed, "elapsed", 0.0);
  2893. X    cpu = end.g_cpu - os_meter_start.g_cpu;
  2894. X    os_meter_ptime(cpu, "usr", elapsed);
  2895. X    io = end.g_io - os_meter_start.g_io;
  2896. X    os_meter_ptime(io, "sys", elapsed);
  2897. X}
  2898. X
  2899. X
  2900. X/*
  2901. X * NAME
  2902. X *    os_legal_path - test if path is legal
  2903. X *
  2904. X * SYNOPSIS
  2905. X *    int os_legal_path(string_ty *path);
  2906. X *
  2907. X * DESCRIPTION
  2908. X *    The os_legal_path function is used to test if each of the components of
  2909. X *    the given path are legal to the underlying operating system.
  2910. X *
  2911. X * RETURNS
  2912. X *    int: zero if it is an illegal path, nonzero it is a legal path.
  2913. X */
  2914. X
  2915. Xint
  2916. Xos_legal_path(str)
  2917. X    string_ty    *str;
  2918. X{
  2919. X    char        *s;
  2920. X    char        *ep;
  2921. X
  2922. X    if (str->str_length < 1 || str->str_length > PATH_MAX)
  2923. X        return 0;
  2924. X    s = str->str_text;
  2925. X    for (;;)
  2926. X    {
  2927. X        ep = strchr(s, '/');
  2928. X        if (!ep)
  2929. X            return (strlen(s) <= NAME_MAX);
  2930. X        if (ep - s > NAME_MAX)
  2931. X            return 0;
  2932. X        s = ep + 1;
  2933. X    }
  2934. X}
  2935. X
  2936. X
  2937. X#ifdef TIMING
  2938. X
  2939. Xstatic long os_totals_baseline;
  2940. X
  2941. Xvoid
  2942. Xos_totals_start()
  2943. X{
  2944. X    struct tms    buffer;
  2945. X
  2946. X    os_totals_baseline = times(&buffer);
  2947. X}
  2948. X
  2949. Xvoid
  2950. Xos_totals()
  2951. X{
  2952. X    struct tms    buffer;
  2953. X    time_t        n;
  2954. X    double        elapsed;
  2955. X    double        t;
  2956. X
  2957. X    error("timing totals...");
  2958. X    n = times(&buffer);
  2959. X    elapsed = (n - os_totals_baseline) / (double)HZ;
  2960. X    os_meter_ptime(elapsed, "elapsed", 0.0);
  2961. X    t = buffer.tms_utime / (double)HZ;
  2962. X    os_meter_ptime(t, "usr", elapsed);
  2963. X    t = buffer.tms_stime / (double)HZ;
  2964. X    os_meter_ptime(t, "sys", elapsed);
  2965. X    t = buffer.tms_cutime / (double)HZ;
  2966. X    os_meter_ptime(t, "cusr", elapsed);
  2967. X    t = buffer.tms_cstime / (double)HZ;
  2968. X    os_meter_ptime(t, "csys", elapsed);
  2969. X}
  2970. X
  2971. X#endif
  2972. END_OF_FILE
  2973. if test 24336 -ne `wc -c <'cook/os.c'`; then
  2974.     echo shar: \"'cook/os.c'\" unpacked with wrong size!
  2975. fi
  2976. # end of 'cook/os.c'
  2977. fi
  2978. if test -f 'cooktime/date.y' -a "${1}" != "-c" ; then 
  2979.   echo shar: Will not clobber existing file \"'cooktime/date.y'\"
  2980. else
  2981. echo shar: Extracting \"'cooktime/date.y'\" \(27036 characters\)
  2982. sed "s/^X//" >'cooktime/date.y' <<'END_OF_FILE'
  2983. X/*
  2984. X * cook - file construction tool
  2985. X * Copyright (C) 1991, 1992, 1993 Peter Miller
  2986. X * All rights reserved.
  2987. X *    Peter Miller <pmiller@bmr.gov.au>
  2988. X *
  2989. X * This code is derived from code which is
  2990. X * Copyright (C) 1986 Steven M. Bellovin
  2991. X *    Steven Bellovin <smb@cs.unc.edu>
  2992. X *
  2993. X * MANIFEST: functions to parse dates
  2994. X */
  2995. X
  2996. X%token    AGO
  2997. X%token    COLON
  2998. X%token    COMMA
  2999. X%token    DAY
  3000. X%token    DAYZONE
  3001. X%token    ID
  3002. X%token    JUNK
  3003. X%token    MERIDIAN
  3004. X%token    MONTH
  3005. X%token    MUNIT
  3006. X%token    NUMBER
  3007. X%token    SLASH
  3008. X%token    SUNIT
  3009. X%token    UNIT
  3010. X%token    ZONE
  3011. X
  3012. X%{
  3013. X
  3014. X#include <stdio.h>
  3015. X#include <stdlib.h>
  3016. X#include <time.h>
  3017. X#include <sys/timeb.h>
  3018. X#include <ctype.h>
  3019. X#include <time.h>
  3020. X#include <string.h>
  3021. X
  3022. X#include <date.h>
  3023. X#include <s-v-arg.h>
  3024. X#include <trace.h>
  3025. X
  3026. X#define daysec (24L * 60L * 60L)
  3027. X
  3028. X#define AM 1
  3029. X#define PM 2
  3030. X
  3031. X#define DAYLIGHT 1
  3032. X#define STANDARD 2
  3033. X#define MAYBE    3
  3034. X
  3035. X#define MAX_ID_LENGTH 20
  3036. X
  3037. Xstatic    int    timeflag;
  3038. Xstatic    int    zoneflag;
  3039. Xstatic    int    dateflag;
  3040. Xstatic    int    dayflag;
  3041. Xstatic    int    relflag;
  3042. Xstatic    time_t    relsec;
  3043. Xstatic    time_t    relmonth;
  3044. Xstatic    int    hh;
  3045. Xstatic    int    mm;
  3046. Xstatic    int    ss;
  3047. Xstatic    int    merid;
  3048. Xstatic    int    day_light_flag;
  3049. Xstatic    int    dayord;
  3050. Xstatic    int    dayreq;
  3051. Xstatic    int    month;
  3052. Xstatic    int    day;
  3053. Xstatic    int    year;
  3054. Xstatic    int    ourzone;
  3055. Xstatic    char    *lptr;
  3056. Xextern    int    yylval;
  3057. Xextern    int    yydebug;
  3058. X
  3059. X
  3060. Xstatic int mdays[12] =
  3061. X{
  3062. X    31, 0, 31,  30, 31, 30,  31, 31, 30,  31, 30, 31
  3063. X};
  3064. X
  3065. X#define epoch 1970
  3066. X
  3067. Xint yyparse _((void)); /* forward */
  3068. X
  3069. X
  3070. X/*
  3071. X * NAME
  3072. X *    table - list of known names
  3073. X *
  3074. X * SYNOPSIS
  3075. X *    table_t table[];
  3076. X *
  3077. X * DESCRIPTION
  3078. X *    The table is used to hold the list of known names.
  3079. X *    This includes time zone names and days of the week, etc.
  3080. X *
  3081. X * CAVEAT
  3082. X *    It is in English.
  3083. X *    It is impossible to have a full list of time zones.
  3084. X */
  3085. X
  3086. Xtypedef struct table_t table_t;
  3087. Xstruct table_t
  3088. X{
  3089. X    char    *name;
  3090. X    int    type;
  3091. X    int    value;
  3092. X};
  3093. X
  3094. X#define HRMIN(a, b) ((a) * 60 + (b))
  3095. X
  3096. Xstatic table_t table[] =
  3097. X{
  3098. X    { "a",        ZONE,        HRMIN(1, 0),    },
  3099. X    { "a.c.s.s.t.",    DAYZONE,    -HRMIN(9, 30),    },
  3100. X    { "a.c.s.t.",    ZONE,        -HRMIN(9, 30),    },
  3101. X    { "a.d.t.",    DAYZONE,    HRMIN(4, 0),    },
  3102. X    { "a.e.s.s.t.",    DAYZONE,    -HRMIN(10, 0),    },
  3103. X    { "a.e.s.t.",    ZONE,        -HRMIN(10, 0),    },
  3104. X    { "a.m.",    MERIDIAN,    AM,        },
  3105. X    { "a.s.t.",    ZONE,        HRMIN(4, 0),    },
  3106. X    { "a.w.s.t.",    ZONE,        -HRMIN(8, 0),    }, /* (no daylight time there,    I'm told */
  3107. X    { "acsst",    DAYZONE,    -HRMIN(9, 30),    }, /* Australian Central Summer */
  3108. X    { "acst",    ZONE,        -HRMIN(9, 30),    }, /* Australian Central Time */
  3109. X    { "adt",    DAYZONE,    HRMIN(4, 0),    },
  3110. X    { "aesst",    DAYZONE,    -HRMIN(10, 0),    }, /* Australian Eastern Summer Time */
  3111. X    { "aest",    ZONE,        -HRMIN(10, 0),    }, /* Australian Eastern Time */
  3112. X    { "ago",    AGO,        1,        },
  3113. X    { "am",        MERIDIAN,    AM,        },
  3114. X    { "apr",    MONTH,        4,        },
  3115. X    { "apr.",    MONTH,        4,        },
  3116. X    { "april",    MONTH,        4,        },
  3117. X    { "ast",    ZONE,        HRMIN(4, 0),    },  /* Atlantic */
  3118. X    { "aug",    MONTH,        8,        },
  3119. X    { "aug.",    MONTH,        8,        },
  3120. X    { "august",    MONTH,        8,        },
  3121. X    { "awst",    ZONE,        -HRMIN(8, 0),    }, /* Australian Western Time */
  3122. X    { "b",        ZONE,        HRMIN(2, 0),    },
  3123. X    { "b.s.t.",    DAYZONE,    HRMIN(0, 0),    },
  3124. X    { "bst",    DAYZONE,    HRMIN(0, 0),    }, /* British Summer Time */
  3125. X    { "c",        ZONE,        HRMIN(3, 0),    },
  3126. X    { "c.d.t.",    DAYZONE,    HRMIN(6, 0),    },
  3127. X    { "c.s.t.",    ZONE,        HRMIN(6, 0),    },
  3128. X    { "cdt",    DAYZONE,    HRMIN(6, 0),    },
  3129. X    { "cst",    ZONE,        HRMIN(6, 0),    }, /* Central */
  3130. X    { "d",        ZONE,        HRMIN(4, 0),    },
  3131. X    { "day",    UNIT,        1 * 24 * 60,    },
  3132. X    { "days",    UNIT,        1 * 24 * 60,    },
  3133. X    { "dec",    MONTH,        12,        },
  3134. X    { "dec.",    MONTH,        12,        },
  3135. X    { "december",    MONTH,        12,        },
  3136. X    { "e",        ZONE,        HRMIN(5, 0),    },
  3137. X    { "e.d.t.",    DAYZONE,    HRMIN(5, 0),    },
  3138. X    { "e.e.s.t.",    DAYZONE,    HRMIN(0, 0),    },
  3139. X    { "e.e.t.",    ZONE,        HRMIN(0, 0),    },
  3140. X    { "e.s.t.",    ZONE,        HRMIN(5, 0),    },
  3141. X    { "edt",    DAYZONE,    HRMIN(5, 0),    },
  3142. X    { "eest",    DAYZONE,    HRMIN(0, 0),    }, /* European Eastern Summer Time */
  3143. X    { "eet",    ZONE,        HRMIN(0, 0),    }, /* European Eastern Time */
  3144. X    { "eigth",    NUMBER,        8,        },
  3145. X    { "eleventh",    NUMBER,        11,        },
  3146. X    { "est",    ZONE,        HRMIN(5, 0),    }, /* Eastern */
  3147. X    { "f",        ZONE,        HRMIN(6, 0),    },
  3148. X    { "feb",    MONTH,        2,        },
  3149. X    { "feb.",    MONTH,        2,        },
  3150. X    { "february",    MONTH,        2,        },
  3151. X    { "fifth",    NUMBER,        5,        },
  3152. X    { "first",    NUMBER,        1,        },
  3153. X    { "fortnight",    UNIT,        14 * 24 * 60,    },
  3154. X    { "fortnights",    UNIT,        14 * 24 * 60,    },
  3155. X    { "fourth",    NUMBER,        4,        },
  3156. X    { "fri",    DAY,        5,        },
  3157. X    { "fri.",    DAY,        5,        },
  3158. X    { "friday",    DAY,        5,        },
  3159. X    { "g",        ZONE,        HRMIN(7, 0),    },
  3160. X    { "g.m.t.",    ZONE,        HRMIN(0, 0),    },
  3161. X    { "gmt",    ZONE,        HRMIN(0, 0),    },
  3162. X    { "h",        ZONE,        HRMIN(8, 0),    },
  3163. X    { "h.d.t.",    DAYZONE,    HRMIN(10, 0),    },
  3164. X    { "h.s.t.",    ZONE,        HRMIN(10, 0),    },
  3165. X    { "hdt",    DAYZONE,    HRMIN(10, 0),    },
  3166. X    { "hour",    UNIT,        60,        },
  3167. X    { "hours",    UNIT,        60,        },
  3168. X    { "hr",        UNIT,        60,        },
  3169. X    { "hrs",    UNIT,        60,        },
  3170. X    { "hst",    ZONE,        HRMIN(10, 0),    }, /* Hawaii */
  3171. X    { "i",        ZONE,        HRMIN(9, 0),    },
  3172. X    { "j.s.t.",    ZONE,        -HRMIN(9, 0),    }, /* Japan Standard Time */
  3173. X    { "jan",    MONTH,        1,        },
  3174. X    { "jan.",    MONTH,        1,        },
  3175. X    { "january",    MONTH,        1,        },
  3176. X    { "jst",    ZONE,        -HRMIN(9, 0),    }, /* Japan Standard Time */
  3177. X    { "jul",    MONTH,        7,        },
  3178. X    { "jul.",    MONTH,        7,        },
  3179. X    { "july",    MONTH,        7,        },
  3180. X    { "jun",    MONTH,        6,        },
  3181. X    { "jun.",    MONTH,        6,        },
  3182. X    { "june",    MONTH,        6,        },
  3183. X    { "k",        ZONE,        HRMIN(10, 0),    },
  3184. X    { "l",        ZONE,        HRMIN(11, 0),    },
  3185. X    { "last",    NUMBER,        -1,        },
  3186. X    { "m",        ZONE,        HRMIN(12, 0),    },
  3187. X    { "m.d.t.",    DAYZONE,    HRMIN(7, 0),    },
  3188. X    { "m.e.s.t.",    DAYZONE,    -HRMIN(1, 0),    },
  3189. X    { "m.e.t.",    ZONE,        -HRMIN(1, 0),    },
  3190. X    { "m.s.t.",    ZONE,        HRMIN(7, 0),    },
  3191. X    { "mar",    MONTH,        3,        },
  3192. X    { "mar.",    MONTH,        3,        },
  3193. X    { "march",    MONTH,        3,        },
  3194. X    { "may",    MONTH,        5,        },
  3195. X    { "mdt",    DAYZONE,    HRMIN(7, 0),    },
  3196. X    { "mest",    DAYZONE,    -HRMIN(1, 0),    }, /* Middle European Summer Time */
  3197. X    { "met",    ZONE,        -HRMIN(1, 0),    }, /* Middle European Time */
  3198. X    { "min",    UNIT,        1,        },
  3199. X    { "mins",    UNIT,        1,        },
  3200. X    { "minute",    UNIT,        1,        },
  3201. X    { "minutes",    UNIT,        1,        },
  3202. X    { "mon",    DAY,        1,        },
  3203. X    { "mon.",    DAY,        1,        },
  3204. X    { "monday",    DAY,        1,        },
  3205. X    { "month",    MUNIT,        1,        },
  3206. X    { "months",    MUNIT,        1,        },
  3207. X    { "mst",    ZONE,        HRMIN(7, 0),    }, /* Mountain */
  3208. X    { "n",        ZONE,        -HRMIN(1, 0),    },
  3209. X    { "n.s.t.",    ZONE,        HRMIN(3, 30),    },
  3210. X    { "next",    NUMBER,        2,        },
  3211. X    { "ninth",    NUMBER,        9,        },
  3212. X    { "nov",    MONTH,        11,        },
  3213. X    { "nov.",    MONTH,        11,        },
  3214. X    { "november",    MONTH,        11,        },
  3215. X    { "now",    UNIT,        0,        },
  3216. X    { "nst",    ZONE,        HRMIN(3, 30),    }, /* Newfoundland */
  3217. X    { "o",        ZONE,        -HRMIN(2, 0),    },
  3218. X    { "oct",    MONTH,        10,        },
  3219. X    { "oct.",    MONTH,        10,        },
  3220. X    { "october",    MONTH,        10,        },
  3221. X    { "p",        ZONE,        -HRMIN(3, 0),    },
  3222. X    { "p.d.t.",    DAYZONE,    HRMIN(8, 0),    },
  3223. X    { "p.m.",    MERIDIAN,    PM,        },
  3224. X    { "p.s.t.",    ZONE,        HRMIN(8, 0),    },
  3225. X    { "pdt",    DAYZONE,    HRMIN(8, 0),    },
  3226. X    { "pm",        MERIDIAN,    PM,        },
  3227. X    { "pst",    ZONE,        HRMIN(8, 0),    }, /* Pacific */
  3228. X    { "q",        ZONE,        -HRMIN(4, 0),    },
  3229. X    { "r",        ZONE,        -HRMIN(5, 0),    },
  3230. X    { "s",        ZONE,        -HRMIN(6, 0),    },
  3231. X    { "sat",    DAY,        6,        },
  3232. X    { "sat.",    DAY,        6,        },
  3233. X    { "saturday",    DAY,        6,        },
  3234. X    { "sec",    SUNIT,        1,        },
  3235. X    { "second",    SUNIT,        1,        },
  3236. X    { "seconds",    SUNIT,        1,        },
  3237. X    { "secs",    SUNIT,        1,        },
  3238. X    { "sep",    MONTH,        9,        },
  3239. X    { "sep.",    MONTH,        9,        },
  3240. X    { "sept",    MONTH,        9,        },
  3241. X    { "sept.",    MONTH,        9,        },
  3242. X    { "september",    MONTH,        9,        },
  3243. X    { "seventh",    NUMBER,        7,        },
  3244. X    { "sixth",    NUMBER,        6,        },
  3245. X    { "sun",    DAY,        0,        },
  3246. X    { "sun.",    DAY,        0,        },
  3247. X    { "sunday",    DAY,        0,        },
  3248. X    { "t",        ZONE,        -HRMIN(7, 0),    },
  3249. X    { "tenth",    NUMBER,        10,        },
  3250. X    { "third",    NUMBER,        3,        },
  3251. X    { "this",    UNIT,        0,        },
  3252. X    { "thu",    DAY,        4,        },
  3253. X    { "thu.",    DAY,        4,        },
  3254. X    { "thur",    DAY,        4,        },
  3255. X    { "thur.",    DAY,        4,        },
  3256. X    { "thurs",    DAY,        4,        },
  3257. X    { "thurs.",    DAY,        4,        },
  3258. X    { "thursday",    DAY,        4,        },
  3259. X    { "today",    UNIT,        0,        },
  3260. X    { "tomorrow",    UNIT,        1 * 24 * 60,    },
  3261. X    { "tue",    DAY,        2,        },
  3262. X    { "tue.",    DAY,        2,        },
  3263. X    { "tues",    DAY,        2,        },
  3264. X    { "tues.",    DAY,        2,        },
  3265. X    { "tuesday",    DAY,        2,        },
  3266. X    { "twelfth",    NUMBER,        12,        },
  3267. X    { "u",        ZONE,        -HRMIN(8, 0),    },
  3268. X    { "u.t.",    ZONE,        HRMIN(0, 0),    },
  3269. X    { "ut",        ZONE,        HRMIN(0, 0),    },
  3270. X    { "v",        ZONE,        -HRMIN(9, 0),    },
  3271. X    { "w",        ZONE,        -HRMIN(10, 0),    },
  3272. X    { "w.e.s.t.",    DAYZONE,    -HRMIN(2, 0),    },
  3273. X    { "w.e.t.",    ZONE,        -HRMIN(2, 0),    },
  3274. X    { "wed",    DAY,        3,        },
  3275. X    { "wed.",    DAY,        3,        },
  3276. X    { "wednes",    DAY,        3,        },
  3277. X    { "wednes.",    DAY,        3,        },
  3278. X    { "wednesday",    DAY,        3,        },
  3279. X    { "week",    UNIT,        7 * 24 * 60,    },
  3280. X    { "weeks",    UNIT,        7 * 24 * 60,    },
  3281. X    { "west",    DAYZONE,    -HRMIN(2, 0),    }, /* Western European Summer Time */
  3282. X    { "wet",    ZONE,        -HRMIN(2, 0),    }, /* Western European Time */
  3283. X    { "x",        ZONE,        -HRMIN(11, 0),    },
  3284. X    { "y",        ZONE,        -HRMIN(12, 0),    },
  3285. X    { "y.d.t.",    DAYZONE,    HRMIN(9, 0),    },
  3286. X    { "y.s.t.",    ZONE,        HRMIN(9, 0),    },
  3287. X    { "ydt",    DAYZONE,    HRMIN(9, 0),    },
  3288. X    { "year",    MUNIT,        12,        },
  3289. X    { "years",    MUNIT,        12,        },
  3290. X    { "yesterday",    UNIT,        -1*24*60,    },
  3291. X    { "yst",    ZONE,        HRMIN(9, 0),    }, /* Yukon */
  3292. X    { "z",        ZONE,        HRMIN(0, 0),    },
  3293. X};
  3294. X
  3295. X
  3296. X/*
  3297. X * NAME
  3298. X *    timeconv - convert a time
  3299. X *
  3300. X * SYNOPSIS
  3301. X *    time_t timeconv(int hh, int mm, int ss, int mer);
  3302. X *
  3303. X * DESCRIPTION
  3304. X *    The timeconv function is used to convert a time
  3305. X *    specified in hours minutes and seconds, into seconds past midnight.
  3306. X *
  3307. X * ARGUMENTS
  3308. X *    hh    hours, range depends on the meridian
  3309. X *    mm    minutes, 0..59
  3310. X *    ss    seconds, 0..59
  3311. X *    mer    meridian to use: AM, PM or 24
  3312. X *
  3313. X * RETURNS
  3314. X *    time_t; seconds past midnight; -1 on any error.
  3315. X */
  3316. X
  3317. Xstatic time_t timeconv _((int hh, int mm, int ss, int mer));
  3318. X
  3319. Xstatic time_t
  3320. Xtimeconv(hh, mm, ss, mer)
  3321. X    int    hh;
  3322. X    int    mm;
  3323. X    int    ss;
  3324. X    int    mer;
  3325. X{
  3326. X    time_t    result;
  3327. X
  3328. X    /*
  3329. X     * perform sanity checks on input
  3330. X     */
  3331. X    trace(("timeconv(hh = %d, mm = %d, ss = %d, mer = %d)\n{\n"/*}*/, hh, mm, ss, mer));
  3332. X    result = -1;
  3333. X    if (mm < 0 || mm > 59 || ss < 0 || ss > 59)
  3334. X        goto done;
  3335. X
  3336. X    /*
  3337. X     * perform range checks depending on the meridian
  3338. X     */
  3339. X    switch (mer)
  3340. X    {
  3341. X    case AM:
  3342. X        if (hh < 1 || hh > 12)
  3343. X            goto done;
  3344. X        if (hh == 12)
  3345. X            hh = 0;
  3346. X        break;
  3347. X
  3348. X    case PM:
  3349. X        if (hh < 1 || hh > 12)
  3350. X            goto done;
  3351. X        if (hh == 12)
  3352. X            hh = 0;
  3353. X        hh += 12;
  3354. X        break;
  3355. X
  3356. X    case 24:
  3357. X        if (hh < 0 || hh > 23)
  3358. X            goto done;
  3359. X        break;
  3360. X
  3361. X    default:
  3362. X        goto done;
  3363. X    }
  3364. X    result = ((hh * 60L + mm) * 60L + ss);
  3365. Xdone:
  3366. X    trace(("return %ld;\n", (long)result));
  3367. X    trace((/*{*/"}\n"));
  3368. X    return result;
  3369. X}
  3370. X
  3371. X
  3372. X/*
  3373. X * NAME
  3374. X *    dateconv - convert a date
  3375. X *
  3376. X * SYNOPSIS
  3377. X *    time_t dateconv(int mm, int dd, int year, int h, int m, int s,
  3378. X *        int mer, int zone, int dayflag);
  3379. X *
  3380. X * DESCRIPTION
  3381. X *    The dateconv function may be used to convert a date after the
  3382. X *    date string has been taken apart by yyparse.
  3383. X *
  3384. X * ARGUMENTS
  3385. X *    mm    month number, in the range 1..12
  3386. X *    year    year number,  in several ranges:
  3387. X *        0..37 means 2000..2037
  3388. X *        70..99 means 1970..1999
  3389. X *        1970..2037 mean themselves.
  3390. X *    dd    day of month, in the range 1..max, where max varies for
  3391. X *        each month, as per the catchy jingle (except February,
  3392. X *        which is a monster).
  3393. X *    h    hours since midnight or meridian
  3394. X *    m    minutes past hour
  3395. X *    s    seconds past minute
  3396. X *    mer    meridian, AM or PM.
  3397. X *    zone    minutes correction for the time zone.
  3398. X *    dayflag    whether to use daylight savings: STANDARD, DAYLIGHT or MAYBE.
  3399. X *
  3400. X * RETURNS
  3401. X *    time_t; the time in seconds past Jan 1 0:00:00 1970 GMT, this will
  3402. X *    always be positive or zero; -1 is returned for any error.
  3403. X *
  3404. X * CAVEAT
  3405. X *    The date functions only work between 1970 and 2037,
  3406. X *    because 0 is Jan 1 00:00:00 1970 GMT
  3407. X *    and (2^31-1) is Jan 19 03:14:07 2038 GMT
  3408. X *    hence some if the weir magic number below.
  3409. X *
  3410. X *    Because -1 is used to represent errors, times before noon Jan 1 1970
  3411. X *    in places east of GMT can't always be represented.
  3412. X */
  3413. X
  3414. Xstatic time_t dateconv _((int mm, int dd, int year, int h, int m, int s,
  3415. X    int mer, int zone, int dayflag));
  3416. X
  3417. Xstatic time_t
  3418. Xdateconv(mm, dd, year, h, m, s, mer, zone, dayflag)
  3419. X    int    mm;
  3420. X    int    dd;
  3421. X    int    year;
  3422. X    int    h;
  3423. X    int    m;
  3424. X    int    s;
  3425. X    int    mer;
  3426. X    int    zone;
  3427. X    int    dayflag;
  3428. X{
  3429. X    time_t    result;
  3430. X    time_t    tod;
  3431. X    time_t    jdate;
  3432. X    int    i;
  3433. X
  3434. X    /*
  3435. X     * make corrections for the year
  3436. X     *
  3437. X     * If it is 0..99, RFC822 says pick closest century.
  3438. X     */
  3439. X    trace(("dateconv(mm = %d, dd = %d, year = %d, h = %d, m = %d, s = %d, mer = %d, zone = %d, dayflag = %d)\n{\n"/*}*/, mm, dd, year, h, m, s, mer, zone, dayflag));
  3440. X    result = -1;
  3441. X    if (year < 0)
  3442. X        year = -year;
  3443. X    if (year < 38)
  3444. X        year += 2000;
  3445. X    else if (year < 100)
  3446. X        year += 1900;
  3447. X
  3448. X    /*
  3449. X     * correct February length once we know the year
  3450. X     */
  3451. X    mdays[1] = 28 + (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
  3452. X
  3453. X    /*
  3454. X     * perform some sanity checks on the input
  3455. X     */
  3456. X    if
  3457. X    (
  3458. X        year < epoch
  3459. X    ||
  3460. X        year >= 2038
  3461. X    ||
  3462. X        mm < 1
  3463. X    ||
  3464. X        mm > 12
  3465. X    ||
  3466. X        dd < 1
  3467. X    ||
  3468. X        dd > mdays[--mm]
  3469. X    )
  3470. X        goto done;
  3471. X
  3472. X    /*
  3473. X     * Determine the julian day number * of the dd-mm-yy given.
  3474. X     * Turn it into seconds, and add in the time zone correction.
  3475. X     */
  3476. X    jdate = dd - 1;
  3477. X        for (i = 0; i < mm; i++)
  3478. X        jdate += mdays[i];
  3479. X    for (i = epoch; i < year; i++)
  3480. X        jdate += 365 + (i % 4 == 0);
  3481. X    jdate *= daysec;
  3482. X    jdate += zone * 60L;
  3483. X
  3484. X    /*
  3485. X     * Determine the time of day.
  3486. X     * that is, seconds from midnight.
  3487. X     * Add it into the julian date.
  3488. X     */
  3489. X    tod = timeconv(h, m, s, mer);
  3490. X    if (tod < 0)
  3491. X        goto done;
  3492. X    jdate += tod;
  3493. X
  3494. X    /*
  3495. X     * Perform daylight savings correction if necessary.
  3496. X     * (This assumes 1 hour daylite savings, which is probably wrong.)
  3497. X     */
  3498. X    if
  3499. X    (
  3500. X        dayflag == DAYLIGHT
  3501. X    ||
  3502. X        (dayflag == MAYBE && localtime(&jdate)->tm_isdst)
  3503. X    )
  3504. X        jdate += -1 * 60 * 60;
  3505. X
  3506. X    /*
  3507. X     * there you have it.
  3508. X     */
  3509. X    result = jdate;
  3510. Xdone:
  3511. X    trace(("return %ld;\n", (long)result));
  3512. X    trace((/*{*/"}\n"));
  3513. X    return result;
  3514. X}
  3515. X
  3516. X
  3517. X/*
  3518. X * NAME
  3519. X *    daylcorr
  3520. X *
  3521. X * SYNOPSIS
  3522. X *    time_t daylcorr(time_t future, time_t now);
  3523. X *
  3524. X * DESCRIPTION
  3525. X *    The daylcorr function is used to determine the difference in seconds
  3526. X *    between two times, taking daylight savings into account.
  3527. X *
  3528. X * ARGUMENTS
  3529. X *    future    - a later time
  3530. X *    now    - an earlier time
  3531. X *
  3532. X * RETURNS
  3533. X *    time_t; the difference in seconds
  3534. X *
  3535. X * CAVEAT
  3536. X *    Assumes daylight savings is alays an integral number of hours.
  3537. X *    This is wrong is Saudi Arabia (time zone changes during the day),
  3538. X *    and South Australia (half hour DLS).
  3539. X */
  3540. X
  3541. Xstatic time_t daylcorr _((time_t future, time_t now));
  3542. X
  3543. Xstatic time_t
  3544. Xdaylcorr(future, now)
  3545. X    time_t    future;
  3546. X    time_t    now;
  3547. X{
  3548. X    int    fdayl;
  3549. X    int    nowdayl;
  3550. X    time_t    result;
  3551. X
  3552. X    trace(("daylcorr(future = %ld, now = %ld)\n{\n"/*}*/, (long)future, (long)now));
  3553. X    nowdayl = (localtime(&now)->tm_hour + 1) % 24;
  3554. X    fdayl = (localtime(&future)->tm_hour + 1) % 24;
  3555. X    result = ((future - now) + 60L * 60L * (nowdayl - fdayl));
  3556. X    trace(("return %ld;\n", (long)result));
  3557. X    trace((/*{*/"}\n"));
  3558. X    return result;
  3559. X}
  3560. X
  3561. X
  3562. X/*
  3563. X * NAME
  3564. X *    dayconv
  3565. X *
  3566. X * SYNOPSIS
  3567. X *    time_t dayconv(int ord, int day, time_t now);
  3568. X *
  3569. X * DESCRIPTION
  3570. X *    The dayconv function is used to convert a day-of-the-week into
  3571. X *    a meaningful time.
  3572. X *
  3573. X * ARGUMENTS
  3574. X *    ord    - the ord'th day from now
  3575. X *    day    - which day of the week
  3576. X *    now    - relative to this
  3577. X *
  3578. X * RETURNS
  3579. X *    time_t; time in seconds from epoch
  3580. X */
  3581. X
  3582. Xstatic time_t dayconv _((int ord, int day, time_t now));
  3583. X
  3584. Xstatic time_t
  3585. Xdayconv(ord, day, now)
  3586. X    int    ord;
  3587. X    int    day;
  3588. X    time_t    now;
  3589. X{
  3590. X    time_t    tod;
  3591. X    time_t    result;
  3592. X
  3593. X    trace(("dayconv(ord = %d, day = %d, now = %ld)\n{\n"/*}*/, ord, day, (long)now));
  3594. X    tod = now;
  3595. X    tod += daysec * ((day - localtime(&tod)->tm_wday + 7) % 7);
  3596. X    tod += 7 * daysec * (ord <= 0 ? ord : ord - 1);
  3597. X    result = daylcorr(tod, now);
  3598. X    trace(("return %ld;\n", (long)result));
  3599. X    trace((/*{*/"}\n"));
  3600. X    return result;
  3601. X}
  3602. X
  3603. X
  3604. X/*
  3605. X * NAME
  3606. X *    monthadd
  3607. X *
  3608. X * SYNOPSIS
  3609. X *    time_t monthadd(time_t sdate, time_t relmonth);
  3610. X *
  3611. X * DESCRIPTION
  3612. X *    The monthadd function is used to add a given number of
  3613. X *    months to a specified time.
  3614. X *
  3615. X * ARGUMENTS
  3616. X *    sdate    - add the months to this
  3617. X *    relmonth - add this many months
  3618. X *
  3619. X * RETURNS
  3620. X *    time_t; seconds since the epoch
  3621. X */
  3622. X
  3623. Xstatic time_t monthadd _((time_t sdate, time_t relmonth));
  3624. X
  3625. Xstatic time_t
  3626. Xmonthadd(sdate, relmonth)
  3627. X    time_t    sdate;
  3628. X    time_t    relmonth;
  3629. X{
  3630. X    struct tm *ltime;
  3631. X    int    mm;
  3632. X    int    year;
  3633. X    time_t    result;
  3634. X
  3635. X    trace(("monthadd(sdate = %ld, relmonth = %ld)\n{\n"/*}*/, (long)sdate, (long)relmonth));
  3636. X    if (relmonth == 0)
  3637. X        result = 0;
  3638. X    else
  3639. X    {
  3640. X        ltime = localtime(&sdate);
  3641. X        mm = 12 * ltime->tm_year + ltime->tm_mon + relmonth;
  3642. X        year = mm / 12;
  3643. X        mm = mm % 12 + 1;
  3644. X        result = 
  3645. X            dateconv
  3646. X            (
  3647. X                mm,
  3648. X                ltime->tm_mday,
  3649. X                year,
  3650. X                ltime->tm_hour,
  3651. X                ltime->tm_min,
  3652. X                ltime->tm_sec,
  3653. X                24,
  3654. X                ourzone,
  3655. X                MAYBE
  3656. X            );
  3657. X        if (result >= 0)
  3658. X            result = daylcorr(result, sdate);
  3659. X    }
  3660. X    trace(("return %ld;\n", (long)result));
  3661. X    trace((/*{*/"}\n"));
  3662. X    return result;
  3663. X}
  3664. X
  3665. X
  3666. X/*
  3667. X * NAME
  3668. X *    lookup - find name
  3669. X *
  3670. X * SYNOPSIS
  3671. X *    int lookup(char *id);
  3672. X *
  3673. X * DESCRIPTION
  3674. X *    The lookup function is used to find a token corresponding to
  3675. X *    a given name.
  3676. X *
  3677. X * ARGUMENTS
  3678. X *    id    - name to search for.  Assumes already downcased.
  3679. X *
  3680. X * RETURNS
  3681. X *    int; yacc token, ID if not found.
  3682. X */
  3683. X
  3684. Xstatic int lookup _((char *id));
  3685. X
  3686. Xstatic int
  3687. Xlookup(id)
  3688. X    char    *id;
  3689. X{
  3690. X    table_t    *tp;
  3691. X    int    min;
  3692. X    int    max;
  3693. X    int    mid;
  3694. X    int    cmp;
  3695. X    int    result;
  3696. X
  3697. X    /*
  3698. X     * binary chop the table
  3699. X     */
  3700. X    trace(("lookup(id = \"%s\")\n{\n"/*}*/, id));
  3701. X    result = ID;
  3702. X    min = 0;
  3703. X    max = SIZEOF(table) - 1;
  3704. X    while (min <= max)
  3705. X    {
  3706. X        mid = (min + max) / 2;
  3707. X        tp = table + mid;
  3708. X        cmp = strcmp(id, tp->name);
  3709. X        if (!cmp)
  3710. X        {
  3711. X            yylval = tp->value;
  3712. X            result = tp->type;
  3713. X            break;
  3714. X        }
  3715. X        if (cmp < 0)
  3716. X            max = mid - 1;
  3717. X        else
  3718. X            min = mid + 1;
  3719. X    }
  3720. X    trace(("return %d;\n", result));
  3721. X    trace((/*{*/"}\n"));
  3722. X    return result;
  3723. X}
  3724. X
  3725. X
  3726. X/*
  3727. X * NAME
  3728. X *    yylex - lexical analyser
  3729. X *
  3730. X * SYNOPSIS
  3731. X *    int yylex(void);
  3732. X *
  3733. X * DESCRIPTION
  3734. X *    The yylex function is used to scan the input string
  3735. X *    and break it into discrete tokens.
  3736. X *
  3737. X * RETURNS
  3738. X *    int; the yacc token, 0 means the-end.
  3739. X */
  3740. X
  3741. Xstatic int yylex _((void));
  3742. X
  3743. Xstatic int
  3744. Xyylex()
  3745. X{
  3746. X    int    sign;
  3747. X    int    c;
  3748. X    char    *p;
  3749. X    char    idbuf[MAX_ID_LENGTH];
  3750. X    int    pcnt;
  3751. X    int    token;
  3752. X
  3753. X    trace(("yylex()\n{\n"/*}*/));
  3754. X    yylval = 0;
  3755. X    for (;;)
  3756. X    {
  3757. X        /*
  3758. X         * get the next input character
  3759. X         */
  3760. X        c = *lptr++;
  3761. X
  3762. X        /*
  3763. X         * action depends on the character
  3764. X         */
  3765. X        switch (c)
  3766. X        {
  3767. X        case 0:
  3768. X            token = 0;
  3769. X            lptr--;
  3770. X            break;
  3771. X
  3772. X        case ' ':
  3773. X        case '\t':
  3774. X            /*
  3775. X             * ignore white space
  3776. X             */
  3777. X            continue;
  3778. X
  3779. X        case ':':
  3780. X            token = COLON;
  3781. X            break;
  3782. X
  3783. X        case ',':
  3784. X            token = COMMA;
  3785. X            break;
  3786. X
  3787. X        case '/':
  3788. X            token = SLASH;
  3789. X            break;
  3790. X
  3791. X        case '-':
  3792. X            if (!isdigit(*lptr))
  3793. X            {
  3794. X                /*
  3795. X                 * ignore lonely '-'s
  3796. X                 */
  3797. X                continue;
  3798. X            }
  3799. X            sign = -1;
  3800. X            c = *lptr++;
  3801. X            goto number;
  3802. X
  3803. X        case '+':
  3804. X            if (!isdigit(*lptr))
  3805. X            {
  3806. X                token = c;
  3807. X                break;
  3808. X            }
  3809. X            sign = 1;
  3810. X            c = *lptr++;
  3811. X            goto number;
  3812. X
  3813. X        case '0': case '1': case '2': case '3': case '4':
  3814. X        case '5': case '6': case '7': case '8': case '9':
  3815. X            /*
  3816. X             * numbers
  3817. X             */
  3818. X            sign = 1;
  3819. X            number:
  3820. X            for (;;)
  3821. X            {
  3822. X                yylval = yylval * 10 + c - '0';
  3823. X                c = *lptr++;
  3824. X                switch (c)
  3825. X                {
  3826. X                case '0': case '1': case '2': case '3':
  3827. X                case '4': case '5': case '6': case '7':
  3828. X                case '8': case '9':
  3829. X                    continue;
  3830. X                }
  3831. X                break;
  3832. X            }
  3833. X            yylval *= sign;
  3834. X            lptr--;
  3835. X            token = NUMBER;
  3836. X            break;
  3837. X        
  3838. X        case 'a': case 'b': case 'c': case 'd': case 'e':
  3839. X        case 'f': case 'g': case 'h': case 'i': case 'j':
  3840. X        case 'k': case 'l': case 'm': case 'n': case 'o':
  3841. X        case 'p': case 'q': case 'r': case 's': case 't':
  3842. X        case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': 
  3843. X        case 'A': case 'B': case 'C': case 'D': case 'E':
  3844. X        case 'F': case 'G': case 'H': case 'I': case 'J':
  3845. X        case 'K': case 'L': case 'M': case 'N': case 'O':
  3846. X        case 'P': case 'Q': case 'R': case 'S': case 'T':
  3847. X        case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': 
  3848. X            /*
  3849. X             * name
  3850. X             */
  3851. X            p = idbuf;
  3852. X            for (;;)
  3853. X            {
  3854. X                if (isupper(c))
  3855. X                    c = tolower(c);
  3856. X                if (p < idbuf + sizeof(idbuf) - 1)
  3857. X                    *p++ = c;
  3858. X                c = *lptr++;
  3859. X                switch (c)
  3860. X                {
  3861. X                case 'a': case 'b': case 'c': case 'd':
  3862. X                case 'e': case 'f': case 'g': case 'h':
  3863. X                case 'i': case 'j': case 'k': case 'l':
  3864. X                case 'm': case 'n': case 'o': case 'p':
  3865. X                case 'q': case 'r': case 's': case 't':
  3866. X                case 'u': case 'v': case 'w': case 'x':
  3867. X                case 'y': case 'z': 
  3868. X                case 'A': case 'B': case 'C': case 'D':
  3869. X                case 'E': case 'F': case 'G': case 'H':
  3870. X                case 'I': case 'J': case 'K': case 'L':
  3871. X                case 'M': case 'N': case 'O': case 'P':
  3872. X                case 'Q': case 'R': case 'S': case 'T':
  3873. X                case 'U': case 'V': case 'W': case 'X':
  3874. X                case 'Y': case 'Z': 
  3875. X                case '.':
  3876. X                    continue;
  3877. X                }
  3878. X                break;
  3879. X            }
  3880. X            *p = 0;
  3881. X            lptr--;
  3882. X            token = lookup(idbuf);
  3883. X            break;
  3884. X        
  3885. X        case '('/*)*/:
  3886. X            /*
  3887. X             * comment
  3888. X             */
  3889. X            for (pcnt = 1; pcnt > 0; )
  3890. X            {
  3891. X                c = *lptr++;
  3892. X                switch (c)
  3893. X                {
  3894. X                case 0:
  3895. X                    --lptr;
  3896. X                    pcnt = 0;
  3897. X                    break;
  3898. X                
  3899. X                case '('/*)*/:
  3900. X                    pcnt++;
  3901. X                    break;
  3902. X
  3903. X                case /*(*/')':
  3904. X                    pcnt--;
  3905. X                    break;
  3906. X                }
  3907. X            }
  3908. X            continue;
  3909. X
  3910. X        default:
  3911. X            /*
  3912. X             * unrecognosed
  3913. X             */
  3914. X            token = JUNK;
  3915. X            break;
  3916. X        }
  3917. X        break;
  3918. X    }
  3919. X    trace(("yylval = %d;\n", yylval));
  3920. X    trace(("return %d;\n", token));
  3921. X    trace((/*{*/"}\n"));
  3922. X    return token;
  3923. X}
  3924. X
  3925. X
  3926. X/*
  3927. X * NAME
  3928. X *    date_scan
  3929. X *
  3930. X * SYNOPSIS
  3931. X *    time_t date_scan(char *s);
  3932. X *
  3933. X * DESCRIPTION
  3934. X *    The date_scan function is used to scan a string and
  3935. X *    return a number of seconds since epoch.
  3936. X *
  3937. X * ARGUMENTS
  3938. X *    s    - string to scan
  3939. X *
  3940. X * RETURNS
  3941. X *    time_t; seconds to epoch, -1 on error.
  3942. X *
  3943. X * CAVEAT
  3944. X *    it isn't psychic
  3945. X */
  3946. X
  3947. Xtime_t
  3948. Xdate_scan(p)
  3949. X    char        *p;
  3950. X{
  3951. X    struct timeb    *now;
  3952. X    struct tm    *lt;
  3953. X    struct timeb    ftz;
  3954. X    time_t        result;
  3955. X    time_t        tod;
  3956. X
  3957. X    /*
  3958. X     * find time zone info, if not given
  3959. X     */
  3960. X    trace(("date_scan(p = \"%s\")\n{\n"/*}*/, p));
  3961. X    lptr = p;
  3962. X    now = &ftz;
  3963. X    ftime(&ftz);
  3964. X
  3965. X    /*
  3966. X     * initialize things
  3967. X     */
  3968. X    lt = localtime(&now->time);
  3969. X    year = lt->tm_year;
  3970. X    month = lt->tm_mon + 1;
  3971. X    day = lt->tm_mday;
  3972. X    relsec = 0;
  3973. X    relmonth = 0;
  3974. X    timeflag = 0;
  3975. X    zoneflag = 0;
  3976. X    dateflag = 0;
  3977. X    dayflag = 0;
  3978. X    relflag = 0;
  3979. X#ifdef CONF_pyramid_broken_ftime
  3980. X    ourzone = now->timezone / 60;
  3981. X#else
  3982. X    ourzone = now->timezone;
  3983. X#endif
  3984. X    day_light_flag = MAYBE;
  3985. X    hh = 0;
  3986. X    mm = 0;
  3987. X    ss = 0;
  3988. X    merid = 24;
  3989. X
  3990. X    /*
  3991. X     * parse the string
  3992. X     */
  3993. X#ifdef DEBUG
  3994. X    yydebug = trace_pretest_;
  3995. X#endif
  3996. X    trace(("yyparse()\n{\n"/*}*/));
  3997. X    result = yyparse();
  3998. X    trace((/*{*/"}\n"));
  3999. X    if (result)
  4000. X    {
  4001. X        result = -1;
  4002. X        goto done;
  4003. X    }
  4004. X
  4005. X    /*
  4006. X     * sanity checks
  4007. X     */
  4008. X    result = -1;
  4009. X    if (timeflag > 1 || zoneflag > 1 || dateflag > 1 || dayflag > 1)
  4010. X        goto done;
  4011. X
  4012. X    if (dateflag || timeflag || dayflag)
  4013. X    {
  4014. X        result =
  4015. X            dateconv
  4016. X            (
  4017. X                month,
  4018. X                day,
  4019. X                year,
  4020. X                hh,
  4021. X                mm,
  4022. X                ss,
  4023. X                merid,
  4024. X                ourzone,
  4025. X                day_light_flag
  4026. X            );
  4027. X        if (result < 0)
  4028. X            goto done;
  4029. X    }
  4030. X    else
  4031. X    {
  4032. X        result = now->time;
  4033. X        if (!relflag)
  4034. X        {
  4035. X            result -=
  4036. X                (
  4037. X                    (lt->tm_hour * 60L + lt->tm_min * 60)
  4038. X                +
  4039. X                    lt->tm_sec
  4040. X                );
  4041. X        }
  4042. X    }
  4043. X
  4044. X    result += relsec;
  4045. X    relsec = monthadd(result, relmonth);
  4046. X    if (relsec < 0)
  4047. X    {
  4048. X        result = -1;
  4049. X        goto done;
  4050. X    }
  4051. X    result += relsec;
  4052. X
  4053. X    if (dayflag && !dateflag)
  4054. X    {
  4055. X        tod = dayconv(dayord, dayreq, result);
  4056. X        result += tod;
  4057. X    }
  4058. X
  4059. X    /*
  4060. X     * here for all exits
  4061. X     */
  4062. Xdone:
  4063. X    trace(("return %ld;\n", (long)result));
  4064. X    trace((/*{*/"}\n"));
  4065. X    return result;
  4066. X}
  4067. X
  4068. X
  4069. X/*
  4070. X * NAME
  4071. X *    date_string - build one
  4072. X *
  4073. X * SYNOPSIS
  4074. X *    char *date_string(time_t when);
  4075. X *
  4076. X * DESCRIPTION
  4077. X *    The date_string function may be used to construct a
  4078. X *    string from a given time in seconds.
  4079. X *
  4080. X *    The string will conform to the RFC822 standard,
  4081. X *    which states a definite preference for GMT dates.
  4082. X *
  4083. X * ARGUMENTS
  4084. X *    when    the time to be rendered.
  4085. X *
  4086. X * RETURNS
  4087. X *    Pointer to string containing rendered time.
  4088. X *    The contents of this string will remain undisturbed
  4089. X *    only until the next call to date_string.
  4090. X */
  4091. X
  4092. Xchar *
  4093. Xdate_string(when)
  4094. X    time_t        when;
  4095. X{
  4096. X    struct tm    *tm;
  4097. X    static char    buffer[32];
  4098. X
  4099. X    static char    *weekday_name[] =
  4100. X    {
  4101. X        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
  4102. X    };
  4103. X
  4104. X    static char    *month_name[] =
  4105. X    {
  4106. X        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  4107. X        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  4108. X    };
  4109. X
  4110. X    /*
  4111. X     * break the given time down into components
  4112. X     *    (RFC1036 likes GMT, remember)
  4113. X     */
  4114. X    trace(("date_string(when = %ld)\n{\n"/*}*/, (long)when));
  4115. X    tm = gmtime(&when);
  4116. X
  4117. X    /*
  4118. X     * build the date string
  4119. X     */
  4120. X    sprintf
  4121. X    (
  4122. X        buffer,
  4123. X        "%s,%3d %s %2.2d %2.2d:%2.2d:%2.2d GMT",
  4124. X        weekday_name[tm->tm_wday],
  4125. X        tm->tm_mday,
  4126. X        month_name[tm->tm_mon],
  4127. X        tm->tm_year % 100,
  4128. X        tm->tm_hour,
  4129. X        tm->tm_min,
  4130. X        tm->tm_sec
  4131. X    );
  4132. X    trace(("return \"%s\";\n", buffer));
  4133. X    trace((/*{*/"}\n"));
  4134. X    return buffer;
  4135. X}
  4136. X
  4137. X
  4138. X/*
  4139. X * NAME
  4140. X *    yyerror
  4141. X *
  4142. X * SYNOPSIS
  4143. X *    void yyerror(char *);
  4144. X *
  4145. X * DESCRIPTION
  4146. X *    The yyerror function is invoked by yacc to report
  4147. X *    errors, but we just throw it away.
  4148. X *
  4149. X * ARGUMENTS
  4150. X *    s    - error to report
  4151. X */
  4152. X
  4153. Xstatic void yyerror _((char *));
  4154. X
  4155. Xstatic void
  4156. Xyyerror(s)
  4157. X    char    *s;
  4158. X{
  4159. X    trace(("yyerror(s = \"%s\")\n{\n"/*}*/, s));
  4160. X    trace((/*{*/"}\n"));
  4161. X}
  4162. X
  4163. X
  4164. X/*
  4165. X * NAME
  4166. X *    yytrace - follow parser actions
  4167. X *
  4168. X * SYNOPSIS
  4169. X *    void yytrace(char *, ...);
  4170. X *
  4171. X * DESCRIPTION
  4172. X *    The yytrace function is used to print the various shifts
  4173. X *    and reductions, etc, done by the yacc-generated parser.
  4174. X *    lines are accumulated and printed whole,
  4175. X *    so as to avoid confusing the trace output.
  4176. X *
  4177. X * ARGUMENTS
  4178. X *    as for printf 
  4179. X *
  4180. X * CAVEAT
  4181. X *    only available when DEBUG is defined
  4182. X */
  4183. X
  4184. X#ifdef DEBUG
  4185. X#define YYDEBUG 1
  4186. X
  4187. X#define printf yytrace
  4188. X
  4189. Xstatic void yytrace _((char *, ...));
  4190. X
  4191. Xstatic void
  4192. Xyytrace(s sva_last)
  4193. X    char        *s;
  4194. X    sva_last_decl
  4195. X{
  4196. X    va_list        ap;
  4197. X    static char    line[1024];
  4198. X    char        buffer[512];
  4199. X    char        *cp;
  4200. X
  4201. X    sva_init(ap, s);
  4202. X    vsprintf(buffer, s, ap);
  4203. X    va_end(ap);
  4204. X    strcat(line, buffer);
  4205. X    cp = line + strlen(line) - 1;
  4206. X    if (cp > line && *cp == '\n')
  4207. X    {
  4208. X        *cp = 0;
  4209. X        trace_printf("%s\n", line);
  4210. X        line[0] = 0;
  4211. X    }
  4212. X}
  4213. X
  4214. X#endif /* DEBUG */
  4215. X
  4216. X%}
  4217. X
  4218. X%%
  4219. X
  4220. Xtimedate
  4221. X    : /* empty */
  4222. X    | timedate item
  4223. X    ;
  4224. X
  4225. Xitem
  4226. X    : TimeSpecification
  4227. X        { timeflag++; }
  4228. X    | TimeZone
  4229. X        { zoneflag++; }
  4230. X    | DateSpecification
  4231. X        { dateflag++; }
  4232. X    | DayOfWeekSpecification
  4233. X        { dayflag++; }
  4234. X    | RelativeSpecification
  4235. X        { relflag++; }
  4236. X    | NumberSpecification
  4237. X    ;
  4238. X
  4239. XNumberSpecification
  4240. X    : NUMBER
  4241. X        {
  4242. X            if (timeflag && dateflag && !relflag)
  4243. X                year = $1;
  4244. X            else
  4245. X            {
  4246. X                timeflag++;
  4247. X                hh = $1 / 100;
  4248. X                mm = $1 % 100;
  4249. X                ss = 0;
  4250. X                merid = 24;
  4251. X            }
  4252. X        }
  4253. X    ;
  4254. X
  4255. XTimeSpecification
  4256. X    : NUMBER MERIDIAN
  4257. X        {
  4258. X            hh = $1;
  4259. X            mm = 0;
  4260. X            ss = 0;
  4261. X            merid = $2;
  4262. X        }
  4263. X    | NUMBER COLON NUMBER
  4264. X        {
  4265. X            hh = $1;
  4266. X            mm = $3;
  4267. X            merid = 24;
  4268. X        }
  4269. X    | NUMBER COLON NUMBER MERIDIAN
  4270. X        {
  4271. X            hh = $1;
  4272. X            mm = $3;
  4273. X            merid = $4;
  4274. X        }
  4275. X    | NUMBER COLON NUMBER NUMBER
  4276. X        {
  4277. X            hh = $1;
  4278. X            mm = $3;
  4279. X            merid = 24;
  4280. X            day_light_flag = STANDARD;
  4281. X            $4 = -$4;
  4282. X            ourzone = $4 % 100 + 60 * $4 / 100;
  4283. X        }
  4284. X    | NUMBER COLON NUMBER COLON NUMBER
  4285. X        {
  4286. X            hh = $1;
  4287. X            mm = $3;
  4288. X            ss = $5;
  4289. X            merid = 24;
  4290. X        }
  4291. X    | NUMBER COLON NUMBER COLON NUMBER MERIDIAN
  4292. X        {
  4293. X            hh = $1;
  4294. X            mm = $3;
  4295. X            ss = $5;
  4296. X            merid = $6;
  4297. X        }
  4298. X    | NUMBER COLON NUMBER COLON NUMBER NUMBER
  4299. X        {
  4300. X            hh = $1;
  4301. X            mm = $3;
  4302. X            ss = $5;
  4303. X            merid = 24;
  4304. X            day_light_flag = STANDARD;
  4305. X            $6 = -$6;
  4306. X            ourzone = $6 % 100 + 60 * $6 / 100;
  4307. X        }
  4308. X    ;
  4309. X
  4310. XTimeZone
  4311. X    : ZONE
  4312. X        {
  4313. X            ourzone = $1;
  4314. X            day_light_flag = STANDARD;
  4315. X        }
  4316. X    | DAYZONE
  4317. X        {
  4318. X            ourzone = $1;
  4319. X            day_light_flag = DAYLIGHT;
  4320. X        }
  4321. X    ;
  4322. X
  4323. XDayOfWeekSpecification
  4324. X    : DAY
  4325. X        {
  4326. X            dayord = 1;
  4327. X            dayreq = $1;
  4328. X        }
  4329. X    | DAY COMMA
  4330. X        {
  4331. X            dayord = 1;
  4332. X            dayreq = $1;
  4333. X        }
  4334. X    | NUMBER DAY
  4335. X        {
  4336. X            dayord = $1;
  4337. X            dayreq = $2;
  4338. X        }
  4339. X    ;
  4340. X
  4341. XDateSpecification
  4342. X    : NUMBER SLASH NUMBER
  4343. X        {
  4344. X            month = $1;
  4345. X            day = $3;
  4346. X        }
  4347. X    | NUMBER SLASH NUMBER SLASH NUMBER
  4348. X        {
  4349. X            month = $1;
  4350. X            day = $3;
  4351. X            year = $5;
  4352. X        }
  4353. X    | MONTH NUMBER
  4354. X        {
  4355. X            month = $1;
  4356. X            day = $2;
  4357. X        }
  4358. X    | MONTH NUMBER COMMA NUMBER
  4359. X        {
  4360. X            month = $1;
  4361. X            day = $2;
  4362. X            year = $4;
  4363. X        }
  4364. X    | NUMBER MONTH
  4365. X        {
  4366. X            month = $2;
  4367. X            day = $1;
  4368. X        }
  4369. X    | NUMBER MONTH NUMBER
  4370. X        {
  4371. X            month = $2;
  4372. X            day = $1;
  4373. X            year = $3;
  4374. X        }
  4375. X    ;
  4376. X
  4377. XRelativeSpecification
  4378. X    : NUMBER UNIT
  4379. X        { relsec +=  60L * $1 * $2; }
  4380. X    | NUMBER MUNIT
  4381. X        { relmonth += $1 * $2; }
  4382. X    | NUMBER SUNIT
  4383. X        { relsec += $1; }
  4384. X    | UNIT
  4385. X        { relsec +=  60L * $1; }
  4386. X    | MUNIT
  4387. X        { relmonth += $1; }
  4388. X    | SUNIT
  4389. X        { relsec++; }
  4390. X    | RelativeSpecification AGO
  4391. X        {
  4392. X            relsec = -relsec;
  4393. X            relmonth = -relmonth;
  4394. X        }
  4395. X    ;
  4396. END_OF_FILE
  4397. if test 27036 -ne `wc -c <'cooktime/date.y'`; then
  4398.     echo shar: \"'cooktime/date.y'\" unpacked with wrong size!
  4399. fi
  4400. # end of 'cooktime/date.y'
  4401. fi
  4402. echo shar: End of archive 9 \(of 11\).
  4403. cp /dev/null ark9isdone
  4404. MISSING=""
  4405. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  4406.     if test ! -f ark${I}isdone ; then
  4407.     MISSING="${MISSING} ${I}"
  4408.     fi
  4409. done
  4410. if test "${MISSING}" = "" ; then
  4411.     echo You have unpacked all 11 archives.
  4412.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  4413. else
  4414.     echo You still need to unpack the following archives:
  4415.     echo "        " ${MISSING}
  4416. fi
  4417. ##  End of shell archive.
  4418. exit 0
  4419.