home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / rcs-5.6 / part04 < prev    next >
Encoding:
Text File  |  1991-12-19  |  80.8 KB  |  2,911 lines

  1. Newsgroups: comp.sources.unix
  2. From: hammer@cs.purdue.edu (Adam Hammer)
  3. Subject: v25i080: rcs-5.6 - Revision Control System, V5.6, Part04/11
  4. Sender: sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: hammer@cs.purdue.edu (Adam Hammer)
  8. Posting-Number: Volume 25, Issue 80
  9. Archive-Name: rcs-5.6/part04
  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 4 (of 11)."
  18. # Contents:  src/COPYING src/partime.c src/rcssyn.c src/rcsutil.c
  19. # Wrapped by vixie@cognition.pa.dec.com on Fri Dec 20 16:23:40 1991
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'src/COPYING' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'src/COPYING'\"
  23. else
  24. echo shar: Extracting \"'src/COPYING'\" \(17982 characters\)
  25. sed "s/^X//" >'src/COPYING' <<'END_OF_FILE'
  26. X            GNU GENERAL PUBLIC LICENSE
  27. X               Version 2, June 1991
  28. X
  29. X Copyright (C) 1989, 1991 Free Software Foundation, Inc.
  30. X                          675 Mass Ave, Cambridge, MA 02139, USA
  31. X Everyone is permitted to copy and distribute verbatim copies
  32. X of this license document, but changing it is not allowed.
  33. X
  34. X                Preamble
  35. X
  36. X  The licenses for most software are designed to take away your
  37. freedom to share and change it.  By contrast, the GNU General Public
  38. License is intended to guarantee your freedom to share and change free
  39. software--to make sure the software is free for all its users.  This
  40. General Public License applies to most of the Free Software
  41. XFoundation's software and to any other program whose authors commit to
  42. using it.  (Some other Free Software Foundation software is covered by
  43. the GNU Library General Public License instead.)  You can apply it to
  44. your programs, too.
  45. X
  46. X  When we speak of free software, we are referring to freedom, not
  47. price.  Our General Public Licenses are designed to make sure that you
  48. have the freedom to distribute copies of free software (and charge for
  49. this service if you wish), that you receive source code or can get it
  50. if you want it, that you can change the software or use pieces of it
  51. in new free programs; and that you know you can do these things.
  52. X
  53. X  To protect your rights, we need to make restrictions that forbid
  54. anyone to deny you these rights or to ask you to surrender the rights.
  55. These restrictions translate to certain responsibilities for you if you
  56. distribute copies of the software, or if you modify it.
  57. X
  58. X  For example, if you distribute copies of such a program, whether
  59. gratis or for a fee, you must give the recipients all the rights that
  60. you have.  You must make sure that they, too, receive or can get the
  61. source code.  And you must show them these terms so they know their
  62. rights.
  63. X
  64. X  We protect your rights with two steps: (1) copyright the software, and
  65. X(2) offer you this license which gives you legal permission to copy,
  66. distribute and/or modify the software.
  67. X
  68. X  Also, for each author's protection and ours, we want to make certain
  69. that everyone understands that there is no warranty for this free
  70. software.  If the software is modified by someone else and passed on, we
  71. want its recipients to know that what they have is not the original, so
  72. that any problems introduced by others will not reflect on the original
  73. authors' reputations.
  74. X
  75. X  Finally, any free program is threatened constantly by software
  76. patents.  We wish to avoid the danger that redistributors of a free
  77. program will individually obtain patent licenses, in effect making the
  78. program proprietary.  To prevent this, we have made it clear that any
  79. patent must be licensed for everyone's free use or not licensed at all.
  80. X
  81. X  The precise terms and conditions for copying, distribution and
  82. modification follow.
  83. X
  84. X            GNU GENERAL PUBLIC LICENSE
  85. X   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  86. X
  87. X  0. This License applies to any program or other work which contains
  88. a notice placed by the copyright holder saying it may be distributed
  89. under the terms of this General Public License.  The "Program", below,
  90. refers to any such program or work, and a "work based on the Program"
  91. means either the Program or any derivative work under copyright law:
  92. that is to say, a work containing the Program or a portion of it,
  93. either verbatim or with modifications and/or translated into another
  94. language.  (Hereinafter, translation is included without limitation in
  95. the term "modification".)  Each licensee is addressed as "you".
  96. X
  97. Activities other than copying, distribution and modification are not
  98. covered by this License; they are outside its scope.  The act of
  99. running the Program is not restricted, and the output from the Program
  100. is covered only if its contents constitute a work based on the
  101. Program (independent of having been made by running the Program).
  102. Whether that is true depends on what the Program does.
  103. X
  104. X  1. You may copy and distribute verbatim copies of the Program's
  105. source code as you receive it, in any medium, provided that you
  106. conspicuously and appropriately publish on each copy an appropriate
  107. copyright notice and disclaimer of warranty; keep intact all the
  108. notices that refer to this License and to the absence of any warranty;
  109. and give any other recipients of the Program a copy of this License
  110. along with the Program.
  111. X
  112. You may charge a fee for the physical act of transferring a copy, and
  113. you may at your option offer warranty protection in exchange for a fee.
  114. X
  115. X  2. You may modify your copy or copies of the Program or any portion
  116. of it, thus forming a work based on the Program, and copy and
  117. distribute such modifications or work under the terms of Section 1
  118. above, provided that you also meet all of these conditions:
  119. X
  120. X    a) You must cause the modified files to carry prominent notices
  121. X    stating that you changed the files and the date of any change.
  122. X
  123. X    b) You must cause any work that you distribute or publish, that in
  124. X    whole or in part contains or is derived from the Program or any
  125. X    part thereof, to be licensed as a whole at no charge to all third
  126. X    parties under the terms of this License.
  127. X
  128. X    c) If the modified program normally reads commands interactively
  129. X    when run, you must cause it, when started running for such
  130. X    interactive use in the most ordinary way, to print or display an
  131. X    announcement including an appropriate copyright notice and a
  132. X    notice that there is no warranty (or else, saying that you provide
  133. X    a warranty) and that users may redistribute the program under
  134. X    these conditions, and telling the user how to view a copy of this
  135. X    License.  (Exception: if the Program itself is interactive but
  136. X    does not normally print such an announcement, your work based on
  137. X    the Program is not required to print an announcement.)
  138. X
  139. These requirements apply to the modified work as a whole.  If
  140. identifiable sections of that work are not derived from the Program,
  141. and can be reasonably considered independent and separate works in
  142. themselves, then this License, and its terms, do not apply to those
  143. sections when you distribute them as separate works.  But when you
  144. distribute the same sections as part of a whole which is a work based
  145. on the Program, the distribution of the whole must be on the terms of
  146. this License, whose permissions for other licensees extend to the
  147. entire whole, and thus to each and every part regardless of who wrote it.
  148. X
  149. Thus, it is not the intent of this section to claim rights or contest
  150. your rights to work written entirely by you; rather, the intent is to
  151. exercise the right to control the distribution of derivative or
  152. collective works based on the Program.
  153. X
  154. In addition, mere aggregation of another work not based on the Program
  155. with the Program (or with a work based on the Program) on a volume of
  156. a storage or distribution medium does not bring the other work under
  157. the scope of this License.
  158. X
  159. X  3. You may copy and distribute the Program (or a work based on it,
  160. under Section 2) in object code or executable form under the terms of
  161. Sections 1 and 2 above provided that you also do one of the following:
  162. X
  163. X    a) Accompany it with the complete corresponding machine-readable
  164. X    source code, which must be distributed under the terms of Sections
  165. X    1 and 2 above on a medium customarily used for software interchange; or,
  166. X
  167. X    b) Accompany it with a written offer, valid for at least three
  168. X    years, to give any third party, for a charge no more than your
  169. X    cost of physically performing source distribution, a complete
  170. X    machine-readable copy of the corresponding source code, to be
  171. X    distributed under the terms of Sections 1 and 2 above on a medium
  172. X    customarily used for software interchange; or,
  173. X
  174. X    c) Accompany it with the information you received as to the offer
  175. X    to distribute corresponding source code.  (This alternative is
  176. X    allowed only for noncommercial distribution and only if you
  177. X    received the program in object code or executable form with such
  178. X    an offer, in accord with Subsection b above.)
  179. X
  180. The source code for a work means the preferred form of the work for
  181. making modifications to it.  For an executable work, complete source
  182. code means all the source code for all modules it contains, plus any
  183. associated interface definition files, plus the scripts used to
  184. control compilation and installation of the executable.  However, as a
  185. special exception, the source code distributed need not include
  186. anything that is normally distributed (in either source or binary
  187. form) with the major components (compiler, kernel, and so on) of the
  188. operating system on which the executable runs, unless that component
  189. itself accompanies the executable.
  190. X
  191. If distribution of executable or object code is made by offering
  192. access to copy from a designated place, then offering equivalent
  193. access to copy the source code from the same place counts as
  194. distribution of the source code, even though third parties are not
  195. compelled to copy the source along with the object code.
  196. X
  197. X  4. You may not copy, modify, sublicense, or distribute the Program
  198. except as expressly provided under this License.  Any attempt
  199. otherwise to copy, modify, sublicense or distribute the Program is
  200. void, and will automatically terminate your rights under this License.
  201. However, parties who have received copies, or rights, from you under
  202. this License will not have their licenses terminated so long as such
  203. parties remain in full compliance.
  204. X
  205. X  5. You are not required to accept this License, since you have not
  206. signed it.  However, nothing else grants you permission to modify or
  207. distribute the Program or its derivative works.  These actions are
  208. prohibited by law if you do not accept this License.  Therefore, by
  209. modifying or distributing the Program (or any work based on the
  210. Program), you indicate your acceptance of this License to do so, and
  211. all its terms and conditions for copying, distributing or modifying
  212. the Program or works based on it.
  213. X
  214. X  6. Each time you redistribute the Program (or any work based on the
  215. Program), the recipient automatically receives a license from the
  216. original licensor to copy, distribute or modify the Program subject to
  217. these terms and conditions.  You may not impose any further
  218. restrictions on the recipients' exercise of the rights granted herein.
  219. You are not responsible for enforcing compliance by third parties to
  220. this License.
  221. X
  222. X  7. If, as a consequence of a court judgment or allegation of patent
  223. infringement or for any other reason (not limited to patent issues),
  224. conditions are imposed on you (whether by court order, agreement or
  225. otherwise) that contradict the conditions of this License, they do not
  226. excuse you from the conditions of this License.  If you cannot
  227. distribute so as to satisfy simultaneously your obligations under this
  228. License and any other pertinent obligations, then as a consequence you
  229. may not distribute the Program at all.  For example, if a patent
  230. license would not permit royalty-free redistribution of the Program by
  231. all those who receive copies directly or indirectly through you, then
  232. the only way you could satisfy both it and this License would be to
  233. refrain entirely from distribution of the Program.
  234. X
  235. If any portion of this section is held invalid or unenforceable under
  236. any particular circumstance, the balance of the section is intended to
  237. apply and the section as a whole is intended to apply in other
  238. circumstances.
  239. X
  240. It is not the purpose of this section to induce you to infringe any
  241. patents or other property right claims or to contest validity of any
  242. such claims; this section has the sole purpose of protecting the
  243. integrity of the free software distribution system, which is
  244. implemented by public license practices.  Many people have made
  245. generous contributions to the wide range of software distributed
  246. through that system in reliance on consistent application of that
  247. system; it is up to the author/donor to decide if he or she is willing
  248. to distribute software through any other system and a licensee cannot
  249. impose that choice.
  250. X
  251. This section is intended to make thoroughly clear what is believed to
  252. be a consequence of the rest of this License.
  253. X
  254. X  8. If the distribution and/or use of the Program is restricted in
  255. certain countries either by patents or by copyrighted interfaces, the
  256. original copyright holder who places the Program under this License
  257. may add an explicit geographical distribution limitation excluding
  258. those countries, so that distribution is permitted only in or among
  259. countries not thus excluded.  In such case, this License incorporates
  260. the limitation as if written in the body of this License.
  261. X
  262. X  9. The Free Software Foundation may publish revised and/or new versions
  263. of the General Public License from time to time.  Such new versions will
  264. be similar in spirit to the present version, but may differ in detail to
  265. address new problems or concerns.
  266. X
  267. XEach version is given a distinguishing version number.  If the Program
  268. specifies a version number of this License which applies to it and "any
  269. later version", you have the option of following the terms and conditions
  270. either of that version or of any later version published by the Free
  271. Software Foundation.  If the Program does not specify a version number of
  272. this License, you may choose any version ever published by the Free Software
  273. XFoundation.
  274. X
  275. X  10. If you wish to incorporate parts of the Program into other free
  276. programs whose distribution conditions are different, write to the author
  277. to ask for permission.  For software which is copyrighted by the Free
  278. Software Foundation, write to the Free Software Foundation; we sometimes
  279. make exceptions for this.  Our decision will be guided by the two goals
  280. of preserving the free status of all derivatives of our free software and
  281. of promoting the sharing and reuse of software generally.
  282. X
  283. X                NO WARRANTY
  284. X
  285. X  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
  286. XFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
  287. OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
  288. PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
  289. OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  290. MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
  291. TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
  292. PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
  293. REPAIR OR CORRECTION.
  294. X
  295. X  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
  296. WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
  297. REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
  298. INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
  299. OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
  300. TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
  301. YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
  302. PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
  303. POSSIBILITY OF SUCH DAMAGES.
  304. X
  305. X             END OF TERMS AND CONDITIONS
  306. X
  307. X    Appendix: How to Apply These Terms to Your New Programs
  308. X
  309. X  If you develop a new program, and you want it to be of the greatest
  310. possible use to the public, the best way to achieve this is to make it
  311. free software which everyone can redistribute and change under these terms.
  312. X
  313. X  To do so, attach the following notices to the program.  It is safest
  314. to attach them to the start of each source file to most effectively
  315. convey the exclusion of warranty; and each file should have at least
  316. the "copyright" line and a pointer to where the full notice is found.
  317. X
  318. X    <one line to give the program's name and a brief idea of what it does.>
  319. X    Copyright (C) 19yy  <name of author>
  320. X
  321. X    This program is free software; you can redistribute it and/or modify
  322. X    it under the terms of the GNU General Public License as published by
  323. X    the Free Software Foundation; either version 2 of the License, or
  324. X    (at your option) any later version.
  325. X
  326. X    This program is distributed in the hope that it will be useful,
  327. X    but WITHOUT ANY WARRANTY; without even the implied warranty of
  328. X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  329. X    GNU General Public License for more details.
  330. X
  331. X    You should have received a copy of the GNU General Public License
  332. X    along with this program; if not, write to the Free Software
  333. X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  334. X
  335. Also add information on how to contact you by electronic and paper mail.
  336. X
  337. If the program is interactive, make it output a short notice like this
  338. when it starts in an interactive mode:
  339. X
  340. X    Gnomovision version 69, Copyright (C) 19yy name of author
  341. X    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
  342. X    This is free software, and you are welcome to redistribute it
  343. X    under certain conditions; type `show c' for details.
  344. X
  345. The hypothetical commands `show w' and `show c' should show the appropriate
  346. parts of the General Public License.  Of course, the commands you use may
  347. be called something other than `show w' and `show c'; they could even be
  348. mouse-clicks or menu items--whatever suits your program.
  349. X
  350. You should also get your employer (if you work as a programmer) or your
  351. school, if any, to sign a "copyright disclaimer" for the program, if
  352. necessary.  Here is a sample; alter the names:
  353. X
  354. X  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  355. X  `Gnomovision' (which makes passes at compilers) written by James Hacker.
  356. X
  357. X  <signature of Ty Coon>, 1 April 1989
  358. X  Ty Coon, President of Vice
  359. X
  360. This General Public License does not permit incorporating your program into
  361. proprietary programs.  If your program is a subroutine library, you may
  362. consider it more useful to permit linking proprietary applications with the
  363. library.  If this is what you want to do, use the GNU Library General
  364. Public License instead of this License.
  365. END_OF_FILE
  366. if test 17982 -ne `wc -c <'src/COPYING'`; then
  367.     echo shar: \"'src/COPYING'\" unpacked with wrong size!
  368. fi
  369. # end of 'src/COPYING'
  370. fi
  371. if test -f 'src/partime.c' -a "${1}" != "-c" ; then 
  372.   echo shar: Will not clobber existing file \"'src/partime.c'\"
  373. else
  374. echo shar: Extracting \"'src/partime.c'\" \(18891 characters\)
  375. sed "s/^X//" >'src/partime.c' <<'END_OF_FILE'
  376. X/*
  377. X * PARTIME        parse date/time string into a TM structure
  378. X *
  379. X * Returns:
  380. X *    0 if parsing failed
  381. X *    else time values in specified TM structure and zone (unspecified values
  382. X *        set to TMNULL)
  383. X * Notes:
  384. X *    This code is quasi-public; it may be used freely in like software.
  385. X *    It is not to be sold, nor used in licensed software without
  386. X *    permission of the author.
  387. X *    For everyone's benefit, please report bugs and improvements!
  388. X *     Copyright 1980 by Ken Harrenstien, SRI International.
  389. X *    (ARPANET: KLH @ SRI)
  390. X */
  391. X
  392. X/* Hacknotes:
  393. X *    If parsing changed so that no backup needed, could perhaps modify
  394. X *        to use a FILE input stream.  Need terminator, though.
  395. X *    Perhaps should return 0 on success, else a non-zero error val?
  396. X */
  397. X
  398. X/* $Log: partime.c,v $
  399. X * Revision 5.6  1991/08/19  03:13:55  eggert
  400. X * Update timezones.
  401. X *
  402. X * Revision 5.5  1991/04/21  11:58:18  eggert
  403. X * Don't put , just before } in initializer.
  404. X *
  405. X * Revision 5.4  1990/10/04  06:30:15  eggert
  406. X * Remove date vs time heuristics that fail between 2000 and 2400.
  407. X * Check for overflow when lexing an integer.
  408. X * Parse 'Jan 10 LT' as 'Jan 10, LT', not 'Jan, 10 LT'.
  409. X *
  410. X * Revision 5.3  1990/09/24  18:56:31  eggert
  411. X * Update timezones.
  412. X *
  413. X * Revision 5.2  1990/09/04  08:02:16  eggert
  414. X * Don't parse two-digit years, because it won't work after 1999/12/31.
  415. X * Don't permit 'Aug Aug'.
  416. X *
  417. X * Revision 5.1  1990/08/29  07:13:49  eggert
  418. X * Be able to parse our own date format.  Don't assume year<10000.
  419. X *
  420. X * Revision 5.0  1990/08/22  08:12:40  eggert
  421. X * Switch to GMT and fix the bugs exposed thereby.  Update timezones.
  422. X * Ansify and Posixate.  Fix peekahead and int-size bugs.
  423. X *
  424. X * Revision 1.4  89/05/01  14:48:46  narten
  425. X * fixed #ifdef DEBUG construct
  426. X * 
  427. X * Revision 1.3  88/08/28  14:53:40  eggert
  428. X * Remove unportable "#endif XXX"s.
  429. X * 
  430. X * Revision 1.2  87/03/27  14:21:53  jenkins
  431. X * Port to suns
  432. X * 
  433. X * Revision 1.1  82/05/06  11:38:26  wft
  434. X * Initial revision
  435. X * 
  436. X */
  437. X
  438. X#include "rcsbase.h"
  439. X
  440. libId(partId, "$Id: partime.c,v 5.6 1991/08/19 03:13:55 eggert Exp $")
  441. X
  442. X#define given(v) (0 <= (v))
  443. X#define TMNULL (-1) /* Items not given are given this value */
  444. X#define TZ_OFFSET (24*60) /* TMNULL  <  zone_offset - TZ_OFFSET */
  445. X
  446. struct tmwent {
  447. X    char const *went;
  448. X    short wval;
  449. X    char wflgs;
  450. X    char wtype;
  451. X};
  452. X    /* wflgs */
  453. X#define TWTIME 02    /* Word is a time value (absence implies date) */
  454. X#define TWDST  04    /* Word is a DST-type timezone */
  455. X    /* wtype */
  456. X#define TM_MON    1    /* month name */
  457. X#define TM_WDAY    2    /* weekday name */
  458. X#define TM_ZON    3    /* time zone name */
  459. X#define TM_LT    4    /* local time */
  460. X#define TM_DST    5    /* daylight savings time */
  461. X#define TM_12    6    /* AM, PM, NOON, or MIDNIGHT */
  462. X    /* wval (for wtype==TM_12) */
  463. X#define T12_AM 1
  464. X#define T12_PM 2
  465. X#define T12_NOON 12
  466. X#define T12_MIDNIGHT 0
  467. X
  468. static struct tmwent const tmwords [] = {
  469. X    {"january",      0, 0, TM_MON},
  470. X    {"february",     1, 0, TM_MON},
  471. X    {"march",        2, 0, TM_MON},
  472. X    {"april",        3, 0, TM_MON},
  473. X    {"may",          4, 0, TM_MON},
  474. X    {"june",         5, 0, TM_MON},
  475. X    {"july",         6, 0, TM_MON},
  476. X    {"august",       7, 0, TM_MON},
  477. X    {"september",    8, 0, TM_MON},
  478. X    {"october",      9, 0, TM_MON},
  479. X    {"november",     10, 0, TM_MON},
  480. X    {"december",     11, 0, TM_MON},
  481. X
  482. X    {"sunday",       0, 0, TM_WDAY},
  483. X    {"monday",       1, 0, TM_WDAY},
  484. X    {"tuesday",      2, 0, TM_WDAY},
  485. X    {"wednesday",    3, 0, TM_WDAY},
  486. X    {"thursday",     4, 0, TM_WDAY},
  487. X    {"friday",       5, 0, TM_WDAY},
  488. X    {"saturday",     6, 0, TM_WDAY},
  489. X
  490. X    {"gmt",          0*60, TWTIME, TM_ZON},   /* Greenwich */
  491. X    {"utc",          0*60, TWTIME, TM_ZON},
  492. X    {"ut",           0*60, TWTIME, TM_ZON},
  493. X    {"cut",         0*60, TWTIME, TM_ZON},
  494. X
  495. X    {"nzst",        -12*60, TWTIME, TM_ZON},  /* New Zealand */
  496. X    {"jst",         -9*60, TWTIME, TM_ZON},   /* Japan */
  497. X    {"kst",         -9*60, TWTIME, TM_ZON},   /* Korea */
  498. X    {"ist",         -5*60-30, TWTIME, TM_ZON},/* India */
  499. X    {"eet",         -2*60, TWTIME, TM_ZON},   /* Eastern Europe */
  500. X    {"cet",         -1*60, TWTIME, TM_ZON},   /* Central Europe */
  501. X    {"met",         -1*60, TWTIME, TM_ZON},   /* Middle Europe */
  502. X    {"wet",          0*60, TWTIME, TM_ZON},   /* Western Europe */
  503. X    {"nst",          3*60+30, TWTIME, TM_ZON},/* Newfoundland */
  504. X    {"ast",          4*60, TWTIME, TM_ZON},   /* Atlantic */
  505. X    {"est",          5*60, TWTIME, TM_ZON},   /* Eastern */
  506. X    {"cst",          6*60, TWTIME, TM_ZON},   /* Central */
  507. X    {"mst",          7*60, TWTIME, TM_ZON},   /* Mountain */
  508. X    {"pst",          8*60, TWTIME, TM_ZON},   /* Pacific */
  509. X    {"akst",         9*60, TWTIME, TM_ZON},   /* Alaska */
  510. X    {"hast",         10*60, TWTIME, TM_ZON},  /* Hawaii-Aleutian */
  511. X    {"hst",          10*60, TWTIME, TM_ZON},  /* Hawaii */
  512. X    {"sst",          11*60, TWTIME, TM_ZON},  /* Samoa */
  513. X
  514. X    {"nzdt",        -12*60, TWTIME+TWDST, TM_ZON},    /* New Zealand */
  515. X    {"kdt",         -9*60, TWTIME+TWDST, TM_ZON},     /* Korea */
  516. X    {"bst",          0*60, TWTIME+TWDST, TM_ZON},     /* Britain */
  517. X    {"ndt",         3*60+30, TWTIME+TWDST, TM_ZON},  /* Newfoundland */
  518. X    {"adt",          4*60, TWTIME+TWDST, TM_ZON},     /* Atlantic */
  519. X    {"edt",          5*60, TWTIME+TWDST, TM_ZON},     /* Eastern */
  520. X    {"cdt",          6*60, TWTIME+TWDST, TM_ZON},     /* Central */
  521. X    {"mdt",          7*60, TWTIME+TWDST, TM_ZON},     /* Mountain */
  522. X    {"pdt",          8*60, TWTIME+TWDST, TM_ZON},     /* Pacific */
  523. X    {"akdt",         9*60, TWTIME+TWDST, TM_ZON},     /* Alaska */
  524. X    {"hadt",         10*60, TWTIME+TWDST, TM_ZON},    /* Hawaii-Aleutian */
  525. X
  526. X#if 0
  527. X    /*
  528. X     * The following names are duplicates or are not well attested.
  529. X     * A standard is needed.
  530. X     */
  531. X    {"east",        -10*60, TWTIME, TM_ZON},  /* Eastern Australia */
  532. X    {"cast",        -9*60-30, TWTIME, TM_ZON},/* Central Australia */
  533. X    {"cst",         -8*60, TWTIME, TM_ZON},   /* China */
  534. X    {"hkt",         -8*60, TWTIME, TM_ZON},   /* Hong Kong */
  535. X    {"sst",         -8*60, TWTIME, TM_ZON},   /* Singapore */
  536. X    {"wast",        -8*60, TWTIME, TM_ZON},   /* Western Australia */
  537. X    {"?",        -6*60-30, TWTIME, TM_ZON},/* Burma */
  538. X    {"?",           -4*60-30, TWTIME, TM_ZON},/* Afghanistan */
  539. X    {"it",          -3*60-30, TWTIME, TM_ZON},/* Iran */
  540. X    {"ist",         -2*60, TWTIME, TM_ZON},   /* Israel */
  541. X    {"mez",        -1*60, TWTIME, TM_ZON},   /* Mittel-Europaeische Zeit */
  542. X    {"ast",          1*60, TWTIME, TM_ZON},   /* Azores */
  543. X    {"fst",          2*60, TWTIME, TM_ZON},   /* Fernando de Noronha */
  544. X    {"bst",          3*60, TWTIME, TM_ZON},   /* Brazil */
  545. X    {"wst",          4*60, TWTIME, TM_ZON},   /* Western Brazil */
  546. X    {"ast",          5*60, TWTIME, TM_ZON},   /* Acre Brazil */
  547. X    {"?",            9*60+30, TWTIME, TM_ZON},/* Marquesas */
  548. X    {"?",         12*60, TWTIME, TM_ZON},  /* Kwajalein */
  549. X
  550. X    {"eadt",        -10*60, TWTIME+TWDST, TM_ZON},    /* Eastern Australia */
  551. X    {"cadt",        -9*60-30, TWTIME+TWDST, TM_ZON},  /* Central Australia */
  552. X    {"cdt",         -8*60, TWTIME+TWDST, TM_ZON},     /* China */
  553. X    {"wadt",        -8*60, TWTIME+TWDST, TM_ZON},     /* Western Australia */
  554. X    {"idt",         -2*60, TWTIME+TWDST, TM_ZON},     /* Israel */
  555. X    {"eest",        -2*60, TWTIME+TWDST, TM_ZON},     /* Eastern Europe */
  556. X    {"cest",        -1*60, TWTIME+TWDST, TM_ZON},     /* Central Europe */
  557. X    {"mest",        -1*60, TWTIME+TWDST, TM_ZON},     /* Middle Europe */
  558. X    {"mesz",    -1*60, TWTIME+TWDST, TM_ZON},      /* Mittel-Europaeische Sommerzeit */
  559. X    {"west",         0*60, TWTIME+TWDST, TM_ZON},     /* Western Europe */
  560. X    {"adt",          1*60, TWTIME+TWDST, TM_ZON},      /* Azores */
  561. X    {"fdt",          2*60, TWTIME+TWDST, TM_ZON},     /* Fernando de Noronha */
  562. X    {"edt",          3*60, TWTIME+TWDST, TM_ZON},     /* Eastern Brazil */
  563. X    {"wdt",          4*60, TWTIME+TWDST, TM_ZON},     /* Western Brazil */
  564. X    {"adt",          5*60, TWTIME+TWDST, TM_ZON},     /* Acre Brazil */
  565. X#endif
  566. X
  567. X    {"lt",           0, TWTIME, TM_LT},       /* local time */
  568. X    {"dst",          1*60, TWTIME, TM_DST},      /* daylight savings time */
  569. X    {"ddst",         2*60, TWTIME, TM_DST},      /* double dst */
  570. X
  571. X    {"am",           T12_AM,    TWTIME, TM_12},
  572. X    {"pm",           T12_PM,    TWTIME, TM_12},
  573. X    {"noon",         T12_NOON,    TWTIME, TM_12},
  574. X    {"midnight",     T12_MIDNIGHT,    TWTIME, TM_12},
  575. X
  576. X    {0, 0, 0, 0}    /* Zero entry to terminate searches */
  577. X};
  578. X
  579. struct token {
  580. X    char const *tcp;/* pointer to string */
  581. X    int tcnt;    /* # chars */
  582. X    char tbrk;    /* "break" char */
  583. X    char tbrkl;    /* last break char */
  584. X    char tflg;    /* 0 = alpha, 1 = numeric */
  585. X    union {         /* Resulting value; */
  586. X        int tnum;/* either a #, or */
  587. X        struct tmwent const *ttmw;/* a ptr to a tmwent.  */
  588. X    } tval;
  589. X};
  590. X
  591. static struct tmwent const*ptmatchstr P((char const*,int,struct tmwent const*));
  592. static int pt12hack P((struct tm *,int));
  593. static int ptitoken P((struct token *));
  594. static int ptstash P((int *,int));
  595. static int pttoken P((struct token *));
  596. X
  597. X    static int
  598. goodzone(t, offset, am)
  599. X    register struct token const *t;
  600. X    int offset;
  601. X    int *am;
  602. X{
  603. X    register int m;
  604. X    if (
  605. X        t->tflg  &&
  606. X        t->tcnt == 4+offset  &&
  607. X        (m = t->tval.tnum) <= 2400  &&
  608. X        isdigit(t->tcp[offset]) &&
  609. X        (m%=100) < 60
  610. X    ) {
  611. X        m += t->tval.tnum/100 * 60;
  612. X        if (t->tcp[offset-1]=='+')
  613. X            m = -m;
  614. X        *am = m;
  615. X        return 1;
  616. X    }
  617. X    return 0;
  618. X}
  619. X
  620. X    int
  621. partime(astr, atm, zone)
  622. char const *astr;
  623. register struct tm *atm;
  624. int *zone;
  625. X{
  626. X    register int i;
  627. X    struct token btoken, atoken;
  628. X    int zone_offset; /* minutes west of GMT, plus TZ_OFFSET */
  629. X    register char const *cp;
  630. X    register char ch;
  631. X    int ord, midnoon;
  632. X    int *atmfield, dst, m;
  633. X    int got1 = 0;
  634. X
  635. X    atm->tm_sec = TMNULL;
  636. X    atm->tm_min = TMNULL;
  637. X    atm->tm_hour = TMNULL;
  638. X    atm->tm_mday = TMNULL;
  639. X    atm->tm_mon = TMNULL;
  640. X    atm->tm_year = TMNULL;
  641. X    atm->tm_wday = TMNULL;
  642. X    atm->tm_yday = TMNULL;
  643. X    midnoon = TMNULL;        /* and our own temp stuff */
  644. X    zone_offset = TMNULL;
  645. X    dst = TMNULL;
  646. X    btoken.tcnt = btoken.tbrk = 0;
  647. X    btoken.tcp = astr;
  648. X
  649. X    for (;; got1=1) {
  650. X    if (!ptitoken(&btoken))                /* Get a token */
  651. X      {     if(btoken.tval.tnum) return(0);         /* Read error? */
  652. X        if (given(midnoon))            /* EOF, wrap up */
  653. X            if (!pt12hack(atm, midnoon))
  654. X                return 0;
  655. X        if (!given(atm->tm_min))
  656. X            atm->tm_min = 0;
  657. X        *zone  =
  658. X                (given(zone_offset) ? zone_offset-TZ_OFFSET : 0)
  659. X            -    (given(dst) ? dst : 0);
  660. X        return got1;
  661. X      }
  662. X    if(btoken.tflg == 0)        /* Alpha? */
  663. X      {     i = btoken.tval.ttmw->wval;
  664. X        switch (btoken.tval.ttmw->wtype) {
  665. X          default:
  666. X            return 0;
  667. X          case TM_MON:
  668. X            atmfield = &atm->tm_mon;
  669. X            break;
  670. X          case TM_WDAY:
  671. X            atmfield = &atm->tm_wday;
  672. X            break;
  673. X          case TM_DST:
  674. X            atmfield = &dst;
  675. X            break;
  676. X          case TM_LT:
  677. X            if (ptstash(&dst, 0))
  678. X                return 0;
  679. X            i = 48*60; /* local time magic number -- see maketime() */
  680. X            /* fall into */
  681. X          case TM_ZON:
  682. X            i += TZ_OFFSET;
  683. X            if (btoken.tval.ttmw->wflgs & TWDST)
  684. X                if (ptstash(&dst, 60))
  685. X                    return 0;
  686. X            /* Peek ahead for offset immediately afterwards. */
  687. X            if (
  688. X                (btoken.tbrk=='-' || btoken.tbrk=='+') &&
  689. X                (atoken=btoken, ++atoken.tcnt, ptitoken(&atoken)) &&
  690. X                goodzone(&atoken, 0, &m)
  691. X            ) {
  692. X                i += m;
  693. X                btoken = atoken;
  694. X            }
  695. X            atmfield = &zone_offset;
  696. X            break;
  697. X          case TM_12:
  698. X            atmfield = &midnoon;
  699. X        }
  700. X        if (ptstash(atmfield, i))
  701. X            return(0);        /* ERR: val already set */
  702. X        continue;
  703. X      }
  704. X
  705. X    /* Token is number.  Lots of hairy heuristics. */
  706. X    if (!isdigit(*btoken.tcp)) {
  707. X        if (!goodzone(&btoken, 1, &m))
  708. X            return 0;
  709. X        zone_offset = TZ_OFFSET + m;
  710. X        continue;
  711. X    }
  712. X
  713. X    i = btoken.tval.tnum;   /* Value now known to be valid; get it. */
  714. X    if (btoken.tcnt == 3)    /*  3 digits = HMM   */
  715. X      {
  716. hhmm4:        if (ptstash(&atm->tm_min, i%100))
  717. X            return(0);        /* ERR: min conflict */
  718. X        i /= 100;
  719. hh2:            if (ptstash(&atm->tm_hour, i))
  720. X            return(0);        /* ERR: hour conflict */
  721. X        continue;
  722. X      }
  723. X
  724. X    if (4 < btoken.tcnt)
  725. X        goto year4; /* far in the future */
  726. X    if(btoken.tcnt == 4)    /* 4 digits = YEAR or HHMM */
  727. X      {    if (given(atm->tm_year)) goto hhmm4;    /* Already got yr? */
  728. X        if (given(atm->tm_hour)) goto year4;    /* Already got hr? */
  729. X        if(btoken.tbrk == ':')            /* HHMM:SS ? */
  730. X            if ( ptstash(&atm->tm_hour, i/100)
  731. X              || ptstash(&atm->tm_min, i%100))
  732. X                return(0);        /* ERR: hr/min clash */
  733. X            else goto coltm2;        /* Go handle SS */
  734. X        if(btoken.tbrk != ',' && btoken.tbrk != '/'
  735. X          && (atoken=btoken, ptitoken(&atoken))    /* Peek */
  736. X          && ( atoken.tflg
  737. X             ? !isdigit(*atoken.tcp)
  738. X             : atoken.tval.ttmw->wflgs & TWTIME)) /* HHMM-ZON */
  739. X            goto hhmm4;
  740. X        goto year4;            /* Give up, assume year. */
  741. X      }
  742. X
  743. X    /* From this point on, assume tcnt == 1 or 2 */
  744. X    /* 2 digits = MM, DD, or HH (MM and SS caught at coltime) */
  745. X    if(btoken.tbrk == ':')        /* HH:MM[:SS] */
  746. X        goto coltime;        /*  must be part of time. */
  747. X    if (31 < i)
  748. X        return 0;
  749. X
  750. X    /* Check for numerical-format date */
  751. X    for (cp = "/-."; ch = *cp++;)
  752. X      {    ord = (ch == '.' ? 0 : 1);    /* n/m = D/M or M/D */
  753. X        if(btoken.tbrk == ch)            /* "NN-" */
  754. X          {    if(btoken.tbrkl != ch)
  755. X              {
  756. X                atoken = btoken;
  757. X                atoken.tcnt++;
  758. X                if (ptitoken(&atoken)
  759. X                  && atoken.tflg == 0
  760. X                  && atoken.tval.ttmw->wtype == TM_MON)
  761. X                    goto dd2;
  762. X                if(ord)goto mm2; else goto dd2; /* "NN-" */
  763. X              }                /* "-NN-" */
  764. X            if (!given(atm->tm_mday)
  765. X              && given(atm->tm_year))    /* If "YYYY-NN-" */
  766. X                goto mm2;        /* then always MM */
  767. X            if(ord)goto dd2; else goto mm2;
  768. X          }
  769. X        if(btoken.tbrkl == ch            /* "-NN" */
  770. X          && given(ord ? atm->tm_mon : atm->tm_mday))
  771. X            if (!given(ord ? atm->tm_mday : atm->tm_mon)) /* MM/DD */
  772. X                if(ord)goto dd2; else goto mm2;
  773. X      }
  774. X
  775. X    /* Now reduced to choice between HH and DD */
  776. X    if (given(atm->tm_hour)) goto dd2;    /* Have hour? Assume day. */
  777. X    if (given(atm->tm_mday)) goto hh2;    /* Have day? Assume hour. */
  778. X    if (given(atm->tm_mon)) goto dd2;    /* Have month? Assume day. */
  779. X    if(i > 24) goto dd2;            /* Impossible HH means DD */
  780. X    atoken = btoken;
  781. X    if (!ptitoken(&atoken))            /* Read ahead! */
  782. X        if(atoken.tval.tnum) return(0); /* ERR: bad token */
  783. X        else goto dd2;            /* EOF, assume day. */
  784. X    if ( atoken.tflg
  785. X       ? !isdigit(*atoken.tcp)
  786. X       : atoken.tval.ttmw->wflgs & TWTIME)
  787. X        /* If next token is a time spec, assume hour */
  788. X        goto hh2;        /* e.g. "3 PM", "11-EDT"  */
  789. X
  790. dd2:    if (ptstash(&atm->tm_mday, i))    /* Store day (1 based) */
  791. X        return(0);
  792. X    continue;
  793. X
  794. mm2:    if (ptstash(&atm->tm_mon, i-1))    /* Store month (make zero based) */
  795. X        return(0);
  796. X    continue;
  797. X
  798. year4:    if ((i-=1900) < 0  ||  ptstash(&atm->tm_year, i)) /* Store year-1900 */
  799. X        return(0);        /* ERR: year conflict */
  800. X    continue;
  801. X
  802. X    /* Hack HH:MM[[:]SS] */
  803. coltime:
  804. X    if (ptstash(&atm->tm_hour, i)) return 0;
  805. X    if (!ptitoken(&btoken))
  806. X        return(!btoken.tval.tnum);
  807. X    if(!btoken.tflg) return(0);    /* ERR: HH:<alpha> */
  808. X    if(btoken.tcnt == 4)        /* MMSS */
  809. X        if (ptstash(&atm->tm_min, btoken.tval.tnum/100)
  810. X          || ptstash(&atm->tm_sec, btoken.tval.tnum%100))
  811. X            return(0);
  812. X        else continue;
  813. X    if(btoken.tcnt != 2
  814. X      || ptstash(&atm->tm_min, btoken.tval.tnum))
  815. X        return(0);        /* ERR: MM bad */
  816. X    if (btoken.tbrk != ':') continue;    /* Seconds follow? */
  817. coltm2:    if (!ptitoken(&btoken))
  818. X        return(!btoken.tval.tnum);
  819. X    if(!btoken.tflg || btoken.tcnt != 2    /* Verify SS */
  820. X      || ptstash(&atm->tm_sec, btoken.tval.tnum))
  821. X        return(0);        /* ERR: SS bad */
  822. X    }
  823. X}
  824. X
  825. X/* Store date/time value, return 0 if successful.
  826. X * Fail if entry is already set.
  827. X */
  828. X    static int
  829. ptstash(adr,val)
  830. int *adr;
  831. int val;
  832. X{    register int *a;
  833. X    if (given(*(a=adr)))
  834. X        return 1;
  835. X    *a = val;
  836. X    return(0);
  837. X}
  838. X
  839. X/* This subroutine is invoked for AM, PM, NOON and MIDNIGHT when wrapping up
  840. X * just prior to returning from partime.
  841. X */
  842. X    static int
  843. pt12hack(tm, aval)
  844. register struct tm *tm;
  845. register int aval;
  846. X{    register int h = tm->tm_hour;
  847. X    switch (aval) {
  848. X      case T12_AM:
  849. X      case T12_PM:
  850. X        if (h > 12)
  851. X            return 0;
  852. X        if (h == 12)
  853. X            tm->tm_hour = 0;
  854. X        if (aval == T12_PM)
  855. X            tm->tm_hour += 12;
  856. X        break;
  857. X      default:
  858. X        if (0 < tm->tm_min  ||  0 < tm->tm_sec)
  859. X            return 0;
  860. X        if (!given(h) || h==12)
  861. X            tm->tm_hour = aval;
  862. X        else if (aval==T12_MIDNIGHT  &&  (h==0 || h==24))
  863. X            return 0;
  864. X    }
  865. X    return 1;
  866. X}
  867. X
  868. X/* Get a token and identify it to some degree.
  869. X * Returns 0 on failure; token.tval will be 0 for normal EOF, otherwise
  870. X * hit error of some sort
  871. X */
  872. X
  873. X    static int
  874. ptitoken(tkp)
  875. register struct token *tkp;
  876. X{
  877. X    register char const *cp;
  878. X    register int i, j, k;
  879. X
  880. X    if (!pttoken(tkp))
  881. X#ifdef DEBUG
  882. X        {
  883. X        VOID printf("EOF\n");
  884. X        return(0);
  885. X        }
  886. X#else
  887. X        return(0);
  888. X#endif    
  889. X    cp = tkp->tcp;
  890. X
  891. X#ifdef DEBUG
  892. X    VOID printf("Token: \"%.*s\" ", tkp->tcnt, cp);
  893. X#endif
  894. X
  895. X    if (tkp->tflg) {
  896. X        i = tkp->tcnt;
  897. X        if (*cp == '+' || *cp == '-') {
  898. X            cp++;
  899. X            i--;
  900. X        }
  901. X        while (0 <= --i) {
  902. X            j = tkp->tval.tnum*10;
  903. X            k = j + (*cp++ - '0');
  904. X            if (j/10 != tkp->tval.tnum  ||  k < j) {
  905. X                /* arithmetic overflow */
  906. X                tkp->tval.tnum = 1;
  907. X                return 0;
  908. X            }
  909. X            tkp->tval.tnum = k;
  910. X        }
  911. X    } else if (!(tkp->tval.ttmw  =  ptmatchstr(cp, tkp->tcnt, tmwords)))
  912. X      {
  913. X#ifdef DEBUG
  914. X        VOID printf("Not found!\n");
  915. X#endif
  916. X        tkp->tval.tnum = 1;
  917. X        return 0;
  918. X      }
  919. X
  920. X#ifdef DEBUG
  921. X    if(tkp->tflg)
  922. X        VOID printf("Val: %d.\n",tkp->tval.tnum);
  923. X    else VOID printf("Found: \"%s\", val: %d, type %d\n",
  924. X        tkp->tval.ttmw->went,tkp->tval.ttmw->wval,tkp->tval.ttmw->wtype);
  925. X#endif
  926. X
  927. X    return(1);
  928. X}
  929. X
  930. X/* Read token from input string into token structure */
  931. X    static int
  932. pttoken(tkp)
  933. register struct token *tkp;
  934. X{
  935. X    register char const *cp;
  936. X    register int c;
  937. X    char const *astr;
  938. X
  939. X    tkp->tcp = astr = cp = tkp->tcp + tkp->tcnt;
  940. X    tkp->tbrkl = tkp->tbrk;        /* Set "last break" */
  941. X    tkp->tcnt = tkp->tbrk = tkp->tflg = 0;
  942. X    tkp->tval.tnum = 0;
  943. X
  944. X    while(c = *cp++)
  945. X      {    switch(c)
  946. X          {    case ' ': case '\t':    /* Flush all whitespace */
  947. X            case '\r': case '\n':
  948. X            case '\v': case '\f':
  949. X                if (!tkp->tcnt) {    /* If no token yet */
  950. X                    tkp->tcp = cp;    /* ignore the brk */
  951. X                    continue;    /* and go on. */
  952. X                }
  953. X                /* fall into */
  954. X            case '(': case ')':    /* Perhaps any non-alphanum */
  955. X            case '-': case ',':    /* shd qualify as break? */
  956. X            case '+':
  957. X            case '/': case ':': case '.':    /* Break chars */
  958. X                if(tkp->tcnt == 0)    /* If no token yet */
  959. X                  {    tkp->tcp = cp;    /* ignore the brk */
  960. X                    tkp->tbrkl = c;
  961. X                      continue;    /* and go on. */
  962. X                  }
  963. X                tkp->tbrk = c;
  964. X                return(tkp->tcnt);
  965. X          }
  966. X        if (!tkp->tcnt++) {        /* If first char of token, */
  967. X            if (isdigit(c)) {
  968. X                tkp->tflg = 1;
  969. X                if (astr<cp-2 && (cp[-2]=='-'||cp[-2]=='+')) {
  970. X                    /* timezone is break+sign+digit */
  971. X                    tkp->tcp--;
  972. X                    tkp->tcnt++;
  973. X                }
  974. X            }
  975. X        } else if ((isdigit(c)!=0) != tkp->tflg) { /* else check type */
  976. X            tkp->tbrk = c;
  977. X            return --tkp->tcnt;    /* Wrong type, back up */
  978. X        }
  979. X      }
  980. X    return(tkp->tcnt);        /* When hit EOF */
  981. X}
  982. X
  983. X
  984. X    static struct tmwent const *
  985. ptmatchstr(astr,cnt,astruc)
  986. X    char const *astr;
  987. X    int cnt;
  988. X    struct tmwent const *astruc;
  989. X{
  990. X    register char const *cp, *mp;
  991. X    register int c;
  992. X    struct tmwent const *lastptr;
  993. X    int i;
  994. X
  995. X    lastptr = 0;
  996. X    for(;mp = astruc->went; astruc += 1)
  997. X      {    cp = astr;
  998. X        for(i = cnt; i > 0; i--)
  999. X          {
  1000. X            switch (*cp++ - (c = *mp++))
  1001. X              {    case 0: continue;    /* Exact match */
  1002. X                case 'A'-'a':
  1003. X                    if (ctab[c] == Letter)
  1004. X                    continue;
  1005. X              }
  1006. X            break;
  1007. X          }
  1008. X        if(i==0)
  1009. X            if (!*mp) return astruc;    /* Exact match */
  1010. X            else if(lastptr) return(0);    /* Ambiguous */
  1011. X            else lastptr = astruc;        /* 1st ambig */
  1012. X      }
  1013. X    return lastptr;
  1014. X}
  1015. END_OF_FILE
  1016. if test 18891 -ne `wc -c <'src/partime.c'`; then
  1017.     echo shar: \"'src/partime.c'\" unpacked with wrong size!
  1018. fi
  1019. # end of 'src/partime.c'
  1020. fi
  1021. if test -f 'src/rcssyn.c' -a "${1}" != "-c" ; then 
  1022.   echo shar: Will not clobber existing file \"'src/rcssyn.c'\"
  1023. else
  1024. echo shar: Extracting \"'src/rcssyn.c'\" \(20108 characters\)
  1025. sed "s/^X//" >'src/rcssyn.c' <<'END_OF_FILE'
  1026. X/*
  1027. X *                     RCS file input
  1028. X */
  1029. X/*********************************************************************************
  1030. X *                       Syntax Analysis.
  1031. X *                       Keyword table
  1032. X *                       Testprogram: define SYNTEST
  1033. X *                       Compatibility with Release 2: define COMPAT2=1
  1034. X *********************************************************************************
  1035. X */
  1036. X
  1037. X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
  1038. X   Copyright 1990, 1991 by Paul Eggert
  1039. X   Distributed under license by the Free Software Foundation, Inc.
  1040. X
  1041. This file is part of RCS.
  1042. X
  1043. RCS is free software; you can redistribute it and/or modify
  1044. it under the terms of the GNU General Public License as published by
  1045. the Free Software Foundation; either version 2, or (at your option)
  1046. any later version.
  1047. X
  1048. RCS is distributed in the hope that it will be useful,
  1049. but WITHOUT ANY WARRANTY; without even the implied warranty of
  1050. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1051. GNU General Public License for more details.
  1052. X
  1053. You should have received a copy of the GNU General Public License
  1054. along with RCS; see the file COPYING.  If not, write to
  1055. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  1056. X
  1057. Report problems and direct all questions to:
  1058. X
  1059. X    rcs-bugs@cs.purdue.edu
  1060. X
  1061. X*/
  1062. X
  1063. X
  1064. X/* $Log: rcssyn.c,v $
  1065. X * Revision 5.8  1991/08/19  03:13:55  eggert
  1066. X * Tune.
  1067. X *
  1068. X * Revision 5.7  1991/04/21  11:58:29  eggert
  1069. X * Disambiguate names on shortname hosts.
  1070. X * Fix errno bug.  Add MS-DOS support.
  1071. X *
  1072. X * Revision 5.6  1991/02/28  19:18:51  eggert
  1073. X * Fix null termination bug in reporting keyword expansion.
  1074. X *
  1075. X * Revision 5.5  1991/02/25  07:12:44  eggert
  1076. X * Check diff output more carefully; avoid overflow.
  1077. X *
  1078. X * Revision 5.4  1990/11/01  05:28:48  eggert
  1079. X * When ignoring unknown phrases, copy them to the output RCS file.
  1080. X * Permit arbitrary data in logs and comment leaders.
  1081. X * Don't check for nontext on initial checkin.
  1082. X *
  1083. X * Revision 5.3  1990/09/20  07:58:32  eggert
  1084. X * Remove the test for non-text bytes; it caused more pain than it cured.
  1085. X *
  1086. X * Revision 5.2  1990/09/04  08:02:30  eggert
  1087. X * Parse RCS files with no revisions.
  1088. X * Don't strip leading white space from diff commands.  Count RCS lines better.
  1089. X *
  1090. X * Revision 5.1  1990/08/29  07:14:06  eggert
  1091. X * Add -kkvl.  Clean old log messages too.
  1092. X *
  1093. X * Revision 5.0  1990/08/22  08:13:44  eggert
  1094. X * Try to parse future RCS formats without barfing.
  1095. X * Add -k.  Don't require final newline.
  1096. X * Remove compile-time limits; use malloc instead.
  1097. X * Don't output branch keyword if there's no default branch,
  1098. X * because RCS version 3 doesn't understand it.
  1099. X * Tune.  Remove lint.
  1100. X * Add support for ISO 8859.  Ansify and Posixate.
  1101. X * Check that a newly checked-in file is acceptable as input to 'diff'.
  1102. X * Check diff's output.
  1103. X *
  1104. X * Revision 4.6  89/05/01  15:13:32  narten
  1105. X * changed copyright header to reflect current distribution rules
  1106. X * 
  1107. X * Revision 4.5  88/08/09  19:13:21  eggert
  1108. X * Allow cc -R; remove lint.
  1109. X * 
  1110. X * Revision 4.4  87/12/18  11:46:16  narten
  1111. X * more lint cleanups (Guy Harris)
  1112. X * 
  1113. X * Revision 4.3  87/10/18  10:39:36  narten
  1114. X * Updating version numbers. Changes relative to 1.1 actually relative to
  1115. X * 4.1
  1116. X * 
  1117. X * Revision 1.3  87/09/24  14:00:49  narten
  1118. X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  1119. X * warnings)
  1120. X * 
  1121. X * Revision 1.2  87/03/27  14:22:40  jenkins
  1122. X * Port to suns
  1123. X * 
  1124. X * Revision 4.1  83/03/28  11:38:49  wft
  1125. X * Added parsing and printing of default branch.
  1126. X * 
  1127. X * Revision 3.6  83/01/15  17:46:50  wft
  1128. X * Changed readdelta() to initialize selector and log-pointer.
  1129. X * Changed puttree to check for selector==DELETE; putdtext() uses DELNUMFORM.
  1130. X *
  1131. X * Revision 3.5  82/12/08  21:58:58  wft
  1132. X * renamed Commentleader to Commleader.
  1133. X *
  1134. X * Revision 3.4  82/12/04  13:24:40  wft
  1135. X * Added routine gettree(), which updates keeplock after reading the
  1136. X * delta tree.
  1137. X *
  1138. X * Revision 3.3  82/11/28  21:30:11  wft
  1139. X * Reading and printing of Suffix removed; version COMPAT2 skips the
  1140. X * Suffix for files of release 2 format. Fixed problems with printing nil.
  1141. X *
  1142. X * Revision 3.2  82/10/18  21:18:25  wft
  1143. X * renamed putdeltatext to putdtext.
  1144. X *
  1145. X * Revision 3.1  82/10/11  19:45:11  wft
  1146. X * made sure getc() returns into an integer.
  1147. X */
  1148. X
  1149. X
  1150. X
  1151. X/* version COMPAT2 reads files of the format of release 2 and 3, but
  1152. X * generates files of release 3 format. Need not be defined if no
  1153. X * old RCS files generated with release 2 exist.
  1154. X */
  1155. X/* version SYNTEST inputs a RCS file and then prints out its internal
  1156. X * data structures.
  1157. X*/
  1158. X
  1159. X#include "rcsbase.h"
  1160. X
  1161. libId(synId, "$Id: rcssyn.c,v 5.8 1991/08/19 03:13:55 eggert Exp $")
  1162. X
  1163. X/* forward */
  1164. static char const *getkeyval P((char const*,enum tokens,int));
  1165. static int strn2expmode P((char const*,size_t));
  1166. X
  1167. X/* keyword table */
  1168. X
  1169. char const
  1170. X    Kdesc[]     = "desc",
  1171. X    Klog[]      = "log",
  1172. X    Ktext[]     = "text";
  1173. X
  1174. static char const
  1175. X    Kaccess[]   = "access",
  1176. X    Kauthor[]   = "author",
  1177. X    Kbranch[]   = "branch",
  1178. X    K_branches[]= "branches",
  1179. X    Kcomment[]  = "comment",
  1180. X    Kdate[]     = "date",
  1181. X    Kexpand[]   = "expand",
  1182. X    Khead[]     = "head",
  1183. X    Klocks[]    = "locks",
  1184. X    Knext[]     = "next",
  1185. X    Kstate[]    = "state",
  1186. X    Kstrict[]   = "strict",
  1187. X#if COMPAT2
  1188. X    Ksuffix[]   = "suffix",
  1189. X#endif
  1190. X    Ksymbols[]  = "symbols";
  1191. X
  1192. static struct buf Commleader;
  1193. static struct cbuf Ignored;
  1194. struct cbuf Comment;
  1195. struct access   * AccessList;
  1196. struct assoc    * Symbols;
  1197. struct lock     * Locks;
  1198. int          Expand;
  1199. int               StrictLocks;
  1200. struct hshentry * Head;
  1201. char const      * Dbranch;
  1202. unsigned TotalDeltas;
  1203. X
  1204. X
  1205. X    static void
  1206. getsemi(key)
  1207. X    char const *key;
  1208. X/* Get a semicolon to finish off a phrase started by KEY.  */
  1209. X{
  1210. X    if (!getlex(SEMI))
  1211. X        fatserror("missing ';' after '%s'", key);
  1212. X}
  1213. X
  1214. X    static struct hshentry *
  1215. getdnum()
  1216. X/* Get a delta number.  */
  1217. X{
  1218. X    register struct hshentry *delta = getnum();
  1219. X    if (delta && countnumflds(delta->num)&1)
  1220. X        fatserror("%s isn't a delta number", delta->num);
  1221. X    return delta;
  1222. X}
  1223. X
  1224. X
  1225. X    void
  1226. getadmin()
  1227. X/* Read an <admin> and initialize the appropriate global variables.  */
  1228. X{
  1229. X    register char const *id;
  1230. X        struct access   * newaccess;
  1231. X        struct assoc    * newassoc;
  1232. X        struct lock     * newlock;
  1233. X        struct hshentry * delta;
  1234. X    struct access **LastAccess;
  1235. X    struct assoc **LastSymbol;
  1236. X    struct lock **LastLock;
  1237. X    struct buf b;
  1238. X    struct cbuf cb;
  1239. X
  1240. X        TotalDeltas=0;
  1241. X
  1242. X    getkey(Khead);
  1243. X    Head = getdnum();
  1244. X    getsemi(Khead);
  1245. X
  1246. X    Dbranch = nil;
  1247. X    if (getkeyopt(Kbranch)) {
  1248. X        if ((delta = getnum()))
  1249. X            Dbranch = delta->num;
  1250. X        getsemi(Kbranch);
  1251. X        }
  1252. X
  1253. X
  1254. X#if COMPAT2
  1255. X        /* read suffix. Only in release 2 format */
  1256. X    if (getkeyopt(Ksuffix)) {
  1257. X                if (nexttok==STRING) {
  1258. X            readstring(); nextlex(); /* Throw away the suffix.  */
  1259. X        } else if (nexttok==ID) {
  1260. X                        nextlex();
  1261. X                }
  1262. X        getsemi(Ksuffix);
  1263. X        }
  1264. X#endif
  1265. X
  1266. X    getkey(Kaccess);
  1267. X    LastAccess = &AccessList;
  1268. X        while (id=getid()) {
  1269. X        newaccess = ftalloc(struct access);
  1270. X                newaccess->login = id;
  1271. X        *LastAccess = newaccess;
  1272. X        LastAccess = &newaccess->nextaccess;
  1273. X        }
  1274. X    *LastAccess = nil;
  1275. X    getsemi(Kaccess);
  1276. X
  1277. X    getkey(Ksymbols);
  1278. X    LastSymbol = &Symbols;
  1279. X        while (id = getid()) {
  1280. X                if (!getlex(COLON))
  1281. X            fatserror("missing ':' in symbolic name definition");
  1282. X                if (!(delta=getnum())) {
  1283. X            fatserror("missing number in symbolic name definition");
  1284. X                } else { /*add new pair to association list*/
  1285. X            newassoc = ftalloc(struct assoc);
  1286. X                        newassoc->symbol=id;
  1287. X            newassoc->num = delta->num;
  1288. X            *LastSymbol = newassoc;
  1289. X            LastSymbol = &newassoc->nextassoc;
  1290. X                }
  1291. X        }
  1292. X    *LastSymbol = nil;
  1293. X    getsemi(Ksymbols);
  1294. X
  1295. X    getkey(Klocks);
  1296. X    LastLock = &Locks;
  1297. X        while (id = getid()) {
  1298. X                if (!getlex(COLON))
  1299. X            fatserror("missing ':' in lock");
  1300. X        if (!(delta=getdnum())) {
  1301. X            fatserror("missing number in lock");
  1302. X                } else { /*add new pair to lock list*/
  1303. X            newlock = ftalloc(struct lock);
  1304. X                        newlock->login=id;
  1305. X                        newlock->delta=delta;
  1306. X            *LastLock = newlock;
  1307. X            LastLock = &newlock->nextlock;
  1308. X                }
  1309. X        }
  1310. X    *LastLock = nil;
  1311. X    getsemi(Klocks);
  1312. X
  1313. X    if ((StrictLocks = getkeyopt(Kstrict)))
  1314. X        getsemi(Kstrict);
  1315. X
  1316. X    Comment.size = 0;
  1317. X    if (getkeyopt(Kcomment)) {
  1318. X        if (nexttok==STRING) {
  1319. X            Comment = savestring(&Commleader);
  1320. X            nextlex();
  1321. X        }
  1322. X        getsemi(Kcomment);
  1323. X        }
  1324. X
  1325. X    Expand = KEYVAL_EXPAND;
  1326. X    if (getkeyopt(Kexpand)) {
  1327. X        if (nexttok==STRING) {
  1328. X            bufautobegin(&b);
  1329. X            cb = savestring(&b);
  1330. X            if ((Expand = strn2expmode(cb.string,cb.size)) < 0)
  1331. X                fatserror("unknown expand mode %.*s",
  1332. X                (int)cb.size, cb.string
  1333. X                );
  1334. X            bufautoend(&b);
  1335. X            nextlex();
  1336. X        }
  1337. X        getsemi(Kexpand);
  1338. X        }
  1339. X    Ignored = getphrases(Kdesc);
  1340. X}
  1341. X
  1342. char const *const expand_names[] = {
  1343. X    /* These must agree with *_EXPAND in rcsbase.h.  */
  1344. X    "kv","kvl","k","v","o",
  1345. X    0
  1346. X};
  1347. X
  1348. X    int
  1349. str2expmode(s)
  1350. X    char const *s;
  1351. X/* Yield expand mode corresponding to S, or -1 if bad.  */
  1352. X{
  1353. X    return strn2expmode(s, strlen(s));
  1354. X}
  1355. X
  1356. X    static int
  1357. strn2expmode(s, n)
  1358. X    char const *s;
  1359. X    size_t n;
  1360. X{
  1361. X    char const *const *p;
  1362. X
  1363. X    for (p = expand_names;  *p;  ++p)
  1364. X        if (memcmp(*p,s,n) == 0  &&  !(*p)[n])
  1365. X            return p - expand_names;
  1366. X    return -1;
  1367. X}
  1368. X
  1369. X
  1370. X    void
  1371. ignorephrase()
  1372. X/* Ignore a phrase introduced by a later version of RCS.  */
  1373. X{
  1374. X    warnignore();
  1375. X    hshenter=false;
  1376. X    for (;;) {
  1377. X        switch (nexttok) {
  1378. X        case SEMI: hshenter=true; nextlex(); return;
  1379. X        case ID:
  1380. X        case NUM: ffree1(NextString); break;
  1381. X        case STRING: readstring(); break;
  1382. X        default: break;
  1383. X        }
  1384. X        nextlex();
  1385. X    }
  1386. X}
  1387. X
  1388. X
  1389. X    static int
  1390. getdelta()
  1391. X/* Function: reads a delta block.
  1392. X * returns false if the current block does not start with a number.
  1393. X */
  1394. X{
  1395. X        register struct hshentry * Delta, * num;
  1396. X    struct branchhead **LastBranch, *NewBranch;
  1397. X
  1398. X    if (!(Delta = getdnum()))
  1399. X        return false;
  1400. X
  1401. X        hshenter = false; /*Don't enter dates into hashtable*/
  1402. X        Delta->date = getkeyval(Kdate, NUM, false);
  1403. X        hshenter=true;    /*reset hshenter for revision numbers.*/
  1404. X
  1405. X        Delta->author = getkeyval(Kauthor, ID, false);
  1406. X
  1407. X        Delta->state = getkeyval(Kstate, ID, true);
  1408. X
  1409. X    getkey(K_branches);
  1410. X    LastBranch = &Delta->branches;
  1411. X    while ((num = getdnum())) {
  1412. X        NewBranch = ftalloc(struct branchhead);
  1413. X                NewBranch->hsh = num;
  1414. X        *LastBranch = NewBranch;
  1415. X        LastBranch = &NewBranch->nextbranch;
  1416. X        }
  1417. X    *LastBranch = nil;
  1418. X    getsemi(K_branches);
  1419. X
  1420. X    getkey(Knext);
  1421. X    Delta->next = num = getdnum();
  1422. X    getsemi(Knext);
  1423. X    Delta->lockedby = nil;
  1424. X    Delta->log.string = 0;
  1425. X    Delta->selector = true;
  1426. X    Delta->ig = getphrases(Kdesc);
  1427. X        TotalDeltas++;
  1428. X        return (true);
  1429. X}
  1430. X
  1431. X
  1432. X    void
  1433. gettree()
  1434. X/* Function: Reads in the delta tree with getdelta(), then
  1435. X * updates the lockedby fields.
  1436. X */
  1437. X{
  1438. X    struct lock const *currlock;
  1439. X
  1440. X        while (getdelta());
  1441. X        currlock=Locks;
  1442. X        while (currlock) {
  1443. X                currlock->delta->lockedby = currlock->login;
  1444. X                currlock = currlock->nextlock;
  1445. X        }
  1446. X}
  1447. X
  1448. X
  1449. X    void
  1450. getdesc(prdesc)
  1451. int  prdesc;
  1452. X/* Function: read in descriptive text
  1453. X * nexttok is not advanced afterwards.
  1454. X * If prdesc is set, the text is printed to stdout.
  1455. X */
  1456. X{
  1457. X
  1458. X    getkeystring(Kdesc);
  1459. X        if (prdesc)
  1460. X                printstring();  /*echo string*/
  1461. X        else    readstring();   /*skip string*/
  1462. X}
  1463. X
  1464. X
  1465. X
  1466. X
  1467. X
  1468. X
  1469. X    static char const *
  1470. getkeyval(keyword, token, optional)
  1471. X    char const *keyword;
  1472. X    enum tokens token;
  1473. X    int optional;
  1474. X/* reads a pair of the form
  1475. X * <keyword> <token> ;
  1476. X * where token is one of <id> or <num>. optional indicates whether
  1477. X * <token> is optional. A pointer to
  1478. X * the actual character string of <id> or <num> is returned.
  1479. X */
  1480. X{
  1481. X    register char const *val = nil;
  1482. X
  1483. X    getkey(keyword);
  1484. X        if (nexttok==token) {
  1485. X                val = NextString;
  1486. X                nextlex();
  1487. X        } else {
  1488. X        if (!optional)
  1489. X            fatserror("missing %s", keyword);
  1490. X        }
  1491. X    getsemi(keyword);
  1492. X        return(val);
  1493. X}
  1494. X
  1495. X
  1496. X
  1497. X
  1498. X    void
  1499. putadmin(fout)
  1500. register FILE * fout;
  1501. X/* Function: Print the <admin> node read with getadmin() to file fout.
  1502. X * Assumption: Variables AccessList, Symbols, Locks, StrictLocks,
  1503. X * and Head have been set.
  1504. X */
  1505. X{
  1506. X    struct assoc const *curassoc;
  1507. X    struct lock const *curlock;
  1508. X    struct access const *curaccess;
  1509. X
  1510. X    aprintf(fout, "%s\t%s;\n", Khead, Head?Head->num:"");
  1511. X    if (Dbranch && VERSION(4)<=RCSversion)
  1512. X        aprintf(fout, "%s\t%s;\n", Kbranch, Dbranch);
  1513. X
  1514. X    aputs(Kaccess, fout);
  1515. X        curaccess = AccessList;
  1516. X        while (curaccess) {
  1517. X           aprintf(fout, "\n\t%s", curaccess->login);
  1518. X               curaccess = curaccess->nextaccess;
  1519. X        }
  1520. X    aprintf(fout, ";\n%s", Ksymbols);
  1521. X        curassoc = Symbols;
  1522. X        while (curassoc) {
  1523. X           aprintf(fout, "\n\t%s:%s", curassoc->symbol, curassoc->num);
  1524. X               curassoc = curassoc->nextassoc;
  1525. X        }
  1526. X    aprintf(fout, ";\n%s", Klocks);
  1527. X        curlock = Locks;
  1528. X        while (curlock) {
  1529. X           aprintf(fout, "\n\t%s:%s", curlock->login, curlock->delta->num);
  1530. X               curlock = curlock->nextlock;
  1531. X        }
  1532. X    if (StrictLocks) aprintf(fout, "; %s", Kstrict);
  1533. X    aprintf(fout, ";\n");
  1534. X    if (Comment.size) {
  1535. X        aprintf(fout, "%s\t", Kcomment);
  1536. X        putstring(fout, true, Comment, false);
  1537. X        aprintf(fout, ";\n");
  1538. X        }
  1539. X    if (Expand != KEYVAL_EXPAND)
  1540. X        aprintf(fout, "%s\t%c%s%c;\n",
  1541. X            Kexpand, SDELIM, expand_names[Expand], SDELIM
  1542. X        );
  1543. X    awrite(Ignored.string, Ignored.size, fout);
  1544. X    aputc('\n', fout);
  1545. X}
  1546. X
  1547. X
  1548. X
  1549. X
  1550. X    static void
  1551. putdelta(node,fout)
  1552. register struct hshentry const *node;
  1553. register FILE * fout;
  1554. X/* Function: prints a <delta> node to fout;
  1555. X */
  1556. X{
  1557. X    struct branchhead const *nextbranch;
  1558. X
  1559. X        if (node == nil) return;
  1560. X
  1561. X    aprintf(fout, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches",
  1562. X        node->num,
  1563. X        Kdate, node->date,
  1564. X        Kauthor, node->author,
  1565. X        Kstate, node->state?node->state:""
  1566. X    );
  1567. X        nextbranch = node->branches;
  1568. X        while (nextbranch) {
  1569. X           aprintf(fout, "\n\t%s", nextbranch->hsh->num);
  1570. X               nextbranch = nextbranch->nextbranch;
  1571. X        }
  1572. X
  1573. X    aprintf(fout, ";\n%s\t%s;\n", Knext, node->next?node->next->num:"");
  1574. X    awrite(node->ig.string, node->ig.size, fout);
  1575. X}
  1576. X
  1577. X
  1578. X
  1579. X
  1580. X    void
  1581. puttree(root,fout)
  1582. struct hshentry const *root;
  1583. register FILE * fout;
  1584. X/* Function: prints the delta tree in preorder to fout, starting with root.
  1585. X */
  1586. X{
  1587. X    struct branchhead const *nextbranch;
  1588. X
  1589. X        if (root==nil) return;
  1590. X
  1591. X    if (root->selector)
  1592. X        putdelta(root,fout);
  1593. X
  1594. X        puttree(root->next,fout);
  1595. X
  1596. X        nextbranch = root->branches;
  1597. X        while (nextbranch) {
  1598. X             puttree(nextbranch->hsh,fout);
  1599. X             nextbranch = nextbranch->nextbranch;
  1600. X        }
  1601. X}
  1602. X
  1603. X
  1604. X    static exiting void
  1605. unexpected_EOF()
  1606. X{
  1607. X    faterror("unexpected EOF in diff output");
  1608. X}
  1609. X
  1610. int putdtext(num,log,srcfilename,fout,diffmt)
  1611. X    char const *num, *srcfilename;
  1612. X    struct cbuf log;
  1613. X    FILE *fout;
  1614. X    int diffmt;
  1615. X/* Function: write a deltatext-node to fout.
  1616. X * num points to the deltanumber, log to the logmessage, and
  1617. X * sourcefile contains the text. Doubles up all SDELIMs in both the
  1618. X * log and the text; Makes sure the log message ends in \n.
  1619. X * returns false on error.
  1620. X * If diffmt is true, also checks that text is valid diff -n output.
  1621. X */
  1622. X{
  1623. X    RILE *fin;
  1624. X    int result;
  1625. X    if (!(fin = Iopen(srcfilename, "r", (struct stat*)0))) {
  1626. X        eerror(srcfilename);
  1627. X        return false;
  1628. X    }
  1629. X    result = putdftext(num,log,fin,fout,diffmt);
  1630. X    Ifclose(fin);
  1631. X    return result;
  1632. X}
  1633. X
  1634. X    void
  1635. putstring(out, delim, s, log)
  1636. X    register FILE *out;
  1637. X    struct cbuf s;
  1638. X    int delim, log;
  1639. X/*
  1640. X * Output to OUT one SDELIM if DELIM, then the string S with SDELIMs doubled.
  1641. X * If LOG is set then S is a log string; append a newline if S is nonempty.
  1642. X */
  1643. X{
  1644. X    register char const *sp;
  1645. X    register size_t ss;
  1646. X
  1647. X    if (delim)
  1648. X        aputc(SDELIM, out);
  1649. X    sp = s.string;
  1650. X    for (ss = s.size;  ss;  --ss) {
  1651. X        if (*sp == SDELIM)
  1652. X            aputc(SDELIM, out);
  1653. X        aputc(*sp++, out);
  1654. X    }
  1655. X    if (s.size && log)
  1656. X        aputc('\n', out);
  1657. X    aputc(SDELIM, out);
  1658. X}
  1659. X
  1660. X    int
  1661. putdftext(num,log,finfile,foutfile,diffmt)
  1662. X    char const *num;
  1663. X    struct cbuf log;
  1664. X    RILE *finfile;
  1665. X    FILE *foutfile;
  1666. X    int diffmt;
  1667. X/* like putdtext(), except the source file is already open */
  1668. X{
  1669. X    declarecache;
  1670. X    register FILE *fout;
  1671. X    register int c;
  1672. X    register RILE *fin;
  1673. X    int ed;
  1674. X    struct diffcmd dc;
  1675. X
  1676. X    fout = foutfile;
  1677. X    aprintf(fout,DELNUMFORM,num,Klog);
  1678. X        /* put log */
  1679. X    putstring(fout, true, log, true);
  1680. X        /* put text */
  1681. X    aprintf(fout, "\n%s\n%c", Ktext, SDELIM);
  1682. X    fin = finfile;
  1683. X    setupcache(fin);
  1684. X    if (!diffmt) {
  1685. X        /* Copy the file */
  1686. X        cache(fin);
  1687. X        for (;;) {
  1688. X        cachegeteof(c, break;);
  1689. X        if (c==SDELIM) aputc(SDELIM,fout);   /*double up SDELIM*/
  1690. X        aputc(c,fout);
  1691. X        }
  1692. X    } else {
  1693. X        initdiffcmd(&dc);
  1694. X        while (0  <=  (ed = getdiffcmd(fin,false,fout,&dc)))
  1695. X        if (ed) {
  1696. X            cache(fin);
  1697. X            while (dc.nlines--)
  1698. X            do {
  1699. X                cachegeteof(c, { if (!dc.nlines) goto OK_EOF; unexpected_EOF(); });
  1700. X                if (c == SDELIM)
  1701. X                aputc(SDELIM,fout);
  1702. X                aputc(c,fout);
  1703. X            } while (c != '\n');
  1704. X            uncache(fin);
  1705. X        }
  1706. X    }
  1707. X    OK_EOF:
  1708. X    aprintf(fout, "%c\n", SDELIM);
  1709. X    return true;
  1710. X}
  1711. X
  1712. X    void
  1713. initdiffcmd(dc)
  1714. X    register struct diffcmd *dc;
  1715. X/* Initialize *dc suitably for getdiffcmd(). */
  1716. X{
  1717. X    dc->adprev = 0;
  1718. X    dc->dafter = 0;
  1719. X}
  1720. X
  1721. X    static exiting void
  1722. badDiffOutput(buf)
  1723. X    char const *buf;
  1724. X{
  1725. X    faterror("bad diff output line: %s", buf);
  1726. X}
  1727. X
  1728. X    static exiting void
  1729. diffLineNumberTooLarge(buf)
  1730. X    char const *buf;
  1731. X{
  1732. X    faterror("diff line number too large: %s", buf);
  1733. X}
  1734. X
  1735. X    int
  1736. getdiffcmd(finfile, delimiter, foutfile, dc)
  1737. X    RILE *finfile;
  1738. X    FILE *foutfile;
  1739. X    int delimiter;
  1740. X    struct diffcmd *dc;
  1741. X/* Get a editing command output by 'diff -n' from fin.
  1742. X * The input is delimited by SDELIM if delimiter is set, EOF otherwise.
  1743. X * Copy a clean version of the command to fout (if nonnull).
  1744. X * Yield 0 for 'd', 1 for 'a', and -1 for EOF.
  1745. X * Store the command's line number and length into dc->line1 and dc->nlines.
  1746. X * Keep dc->adprev and dc->dafter up to date.
  1747. X */
  1748. X{
  1749. X    register int c;
  1750. X    declarecache;
  1751. X    register FILE *fout;
  1752. X    register char *p;
  1753. X    register RILE *fin;
  1754. X    unsigned long line1, nlines, t;
  1755. X    char buf[BUFSIZ];
  1756. X
  1757. X    fin = finfile;
  1758. X    fout = foutfile;
  1759. X    setupcache(fin); cache(fin);
  1760. X    cachegeteof(c, { if (delimiter) unexpected_EOF(); return -1; } );
  1761. X    if (delimiter) {
  1762. X        if (c==SDELIM) {
  1763. X            cacheget(c);
  1764. X            if (c==SDELIM) {
  1765. X                buf[0] = c;
  1766. X                buf[1] = 0;
  1767. X                badDiffOutput(buf);
  1768. X            }
  1769. X            uncache(fin);
  1770. X            nextc = c;
  1771. X            if (fout)
  1772. X                aprintf(fout, "%c%c", SDELIM, c);
  1773. X            return -1;
  1774. X        }
  1775. X    }
  1776. X    p = buf;
  1777. X    do {
  1778. X        if (buf+BUFSIZ-2 <= p) {
  1779. X            faterror("diff output command line too long");
  1780. X        }
  1781. X        *p++ = c;
  1782. X        cachegeteof(c, unexpected_EOF();) ;
  1783. X    } while (c != '\n');
  1784. X    uncache(fin);
  1785. X    if (delimiter)
  1786. X        ++rcsline;
  1787. X    *p = '\0';
  1788. X    for (p = buf+1;  (c = *p++) == ' ';  )
  1789. X        ;
  1790. X    line1 = 0;
  1791. X    while (isdigit(c)) {
  1792. X        t = line1 * 10;
  1793. X        if (
  1794. X            ULONG_MAX/10 < line1  ||
  1795. X            (line1 = t + (c - '0'))  <  t
  1796. X        )
  1797. X            diffLineNumberTooLarge(buf);
  1798. X        c = *p++;
  1799. X    }
  1800. X    while (c == ' ')
  1801. X        c = *p++;
  1802. X    nlines = 0;
  1803. X    while (isdigit(c)) {
  1804. X        t = nlines * 10;
  1805. X        if (
  1806. X            ULONG_MAX/10 < nlines  ||
  1807. X            (nlines = t + (c - '0'))  <  t
  1808. X        )
  1809. X            diffLineNumberTooLarge(buf);
  1810. X        c = *p++;
  1811. X    }
  1812. X    if (c || !nlines) {
  1813. X        badDiffOutput(buf);
  1814. X    }
  1815. X    if (line1+nlines < line1)
  1816. X        diffLineNumberTooLarge(buf);
  1817. X    switch (buf[0]) {
  1818. X        case 'a':
  1819. X        if (line1 < dc->adprev) {
  1820. X            faterror("backward insertion in diff output: %s", buf);
  1821. X        }
  1822. X        dc->adprev = line1 + 1;
  1823. X        break;
  1824. X        case 'd':
  1825. X        if (line1 < dc->adprev  ||  line1 < dc->dafter) {
  1826. X            faterror("backward deletion in diff output: %s", buf);
  1827. X        }
  1828. X        dc->adprev = line1;
  1829. X        dc->dafter = line1 + nlines;
  1830. X        break;
  1831. X        default:
  1832. X        badDiffOutput(buf);
  1833. X    }
  1834. X    if (fout) {
  1835. X        aprintf(fout, "%s\n", buf);
  1836. X    }
  1837. X    dc->line1 = line1;
  1838. X    dc->nlines = nlines;
  1839. X    return buf[0] == 'a';
  1840. X}
  1841. X
  1842. X
  1843. X
  1844. X#ifdef SYNTEST
  1845. X
  1846. char const cmdid[] = "syntest";
  1847. X
  1848. X    int
  1849. main(argc,argv)
  1850. int argc; char * argv[];
  1851. X{
  1852. X
  1853. X        if (argc<2) {
  1854. X        aputs("No input file\n",stderr);
  1855. X        exitmain(EXIT_FAILURE);
  1856. X        }
  1857. X    if (!(finptr = Iopen(argv[1], FOPEN_R, (struct stat*)0))) {
  1858. X        faterror("can't open input file %s", argv[1]);
  1859. X        }
  1860. X        Lexinit();
  1861. X        getadmin();
  1862. X        putadmin(stdout);
  1863. X
  1864. X        gettree();
  1865. X        puttree(Head,stdout);
  1866. X
  1867. X        getdesc(true);
  1868. X
  1869. X    nextlex();
  1870. X
  1871. X    if (!eoflex()) {
  1872. X        fatserror("expecting EOF");
  1873. X        }
  1874. X    exitmain(EXIT_SUCCESS);
  1875. X}
  1876. X
  1877. X
  1878. exiting void exiterr() { _exit(EXIT_FAILURE); }
  1879. X
  1880. X
  1881. X#endif
  1882. X
  1883. END_OF_FILE
  1884. if test 20108 -ne `wc -c <'src/rcssyn.c'`; then
  1885.     echo shar: \"'src/rcssyn.c'\" unpacked with wrong size!
  1886. fi
  1887. # end of 'src/rcssyn.c'
  1888. fi
  1889. if test -f 'src/rcsutil.c' -a "${1}" != "-c" ; then 
  1890.   echo shar: Will not clobber existing file \"'src/rcsutil.c'\"
  1891. else
  1892. echo shar: Extracting \"'src/rcsutil.c'\" \(20392 characters\)
  1893. sed "s/^X//" >'src/rcsutil.c' <<'END_OF_FILE'
  1894. X/*
  1895. X *                     RCS utilities
  1896. X */
  1897. X
  1898. X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
  1899. X   Copyright 1990, 1991 by Paul Eggert
  1900. X   Distributed under license by the Free Software Foundation, Inc.
  1901. X
  1902. This file is part of RCS.
  1903. X
  1904. RCS is free software; you can redistribute it and/or modify
  1905. it under the terms of the GNU General Public License as published by
  1906. the Free Software Foundation; either version 2, or (at your option)
  1907. any later version.
  1908. X
  1909. RCS is distributed in the hope that it will be useful,
  1910. but WITHOUT ANY WARRANTY; without even the implied warranty of
  1911. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1912. GNU General Public License for more details.
  1913. X
  1914. You should have received a copy of the GNU General Public License
  1915. along with RCS; see the file COPYING.  If not, write to
  1916. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  1917. X
  1918. Report problems and direct all questions to:
  1919. X
  1920. X    rcs-bugs@cs.purdue.edu
  1921. X
  1922. X*/
  1923. X
  1924. X
  1925. X
  1926. X
  1927. X/* $Log: rcsutil.c,v $
  1928. X * Revision 5.10  1991/10/07  17:32:46  eggert
  1929. X * Support piece tables even if !has_mmap.
  1930. X *
  1931. X * Revision 5.9  1991/08/19  03:13:55  eggert
  1932. X * Add spawn() support.  Explicate assumptions about getting invoker's name.
  1933. X * Standardize user-visible dates.  Tune.
  1934. X *
  1935. X * Revision 5.8  1991/04/21  11:58:30  eggert
  1936. X * Plug setuid security hole.
  1937. X *
  1938. X * Revision 5.6  1991/02/26  17:48:39  eggert
  1939. X * Fix setuid bug.  Use fread, fwrite more portably.
  1940. X * Support waitpid.  Don't assume -1 is acceptable to W* macros.
  1941. X * strsave -> str_save (DG/UX name clash)
  1942. X *
  1943. X * Revision 5.5  1990/12/04  05:18:49  eggert
  1944. X * Don't output a blank line after a signal diagnostic.
  1945. X * Use -I for prompts and -q for diagnostics.
  1946. X *
  1947. X * Revision 5.4  1990/11/01  05:03:53  eggert
  1948. X * Remove unneeded setid check.  Add awrite(), fremember().
  1949. X *
  1950. X * Revision 5.3  1990/10/06  00:16:45  eggert
  1951. X * Don't fread F if feof(F).
  1952. X *
  1953. X * Revision 5.2  1990/09/04  08:02:31  eggert
  1954. X * Store fread()'s result in an fread_type object.
  1955. X *
  1956. X * Revision 5.1  1990/08/29  07:14:07  eggert
  1957. X * Declare getpwuid() more carefully.
  1958. X *
  1959. X * Revision 5.0  1990/08/22  08:13:46  eggert
  1960. X * Add setuid support.  Permit multiple locks per user.
  1961. X * Remove compile-time limits; use malloc instead.
  1962. X * Switch to GMT.  Permit dates past 1999/12/31.
  1963. X * Add -V.  Remove snooping.  Ansify and Posixate.
  1964. X * Tune.  Some USG hosts define NSIG but not sys_siglist.
  1965. X * Don't run /bin/sh if it's hopeless.
  1966. X * Don't leave garbage behind if the output is an empty pipe.
  1967. X * Clean up after SIGXCPU or SIGXFSZ.  Print name of signal that caused cleanup.
  1968. X *
  1969. X * Revision 4.6  89/05/01  15:13:40  narten
  1970. X * changed copyright header to reflect current distribution rules
  1971. X * 
  1972. X * Revision 4.5  88/11/08  16:01:02  narten
  1973. X * corrected use of varargs routines
  1974. X * 
  1975. X * Revision 4.4  88/08/09  19:13:24  eggert
  1976. X * Check for memory exhaustion.
  1977. X * Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch.
  1978. X * Use execv(), not system(); yield exit status like diff(1)'s.
  1979. X * 
  1980. X * Revision 4.3  87/10/18  10:40:22  narten
  1981. X * Updating version numbers. Changes relative to 1.1 actually
  1982. X * relative to 4.1
  1983. X * 
  1984. X * Revision 1.3  87/09/24  14:01:01  narten
  1985. X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  1986. X * warnings)
  1987. X * 
  1988. X * Revision 1.2  87/03/27  14:22:43  jenkins
  1989. X * Port to suns
  1990. X * 
  1991. X * Revision 4.1  83/05/10  15:53:13  wft
  1992. X * Added getcaller() and findlock().
  1993. X * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal
  1994. X * (needed for background jobs in older shells). Added restoreints().
  1995. X * Removed printing of full RCS path from logcommand().
  1996. X * 
  1997. X * Revision 3.8  83/02/15  15:41:49  wft
  1998. X * Added routine fastcopy() to copy remainder of a file in blocks.
  1999. X *
  2000. X * Revision 3.7  82/12/24  15:25:19  wft
  2001. X * added catchints(), ignoreints() for catching and ingnoring interrupts;
  2002. X * fixed catchsig().
  2003. X *
  2004. X * Revision 3.6  82/12/08  21:52:05  wft
  2005. X * Using DATEFORM to format dates.
  2006. X *
  2007. X * Revision 3.5  82/12/04  18:20:49  wft
  2008. X * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update
  2009. X * lockedby-field.
  2010. X *
  2011. X * Revision 3.4  82/12/03  17:17:43  wft
  2012. X * Added check to addlock() ensuring only one lock per person.
  2013. X * Addlock also returns a pointer to the lock created. Deleted fancydate().
  2014. X *
  2015. X * Revision 3.3  82/11/27  12:24:37  wft
  2016. X * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c.
  2017. X * Introduced macro SNOOP so that snoop can be placed in directory other than
  2018. X * TARGETDIR. Changed %02d to %.2d for compatibility reasons.
  2019. X *
  2020. X * Revision 3.2  82/10/18  21:15:11  wft
  2021. X * added function getfullRCSname().
  2022. X *
  2023. X * Revision 3.1  82/10/13  16:17:37  wft
  2024. X * Cleanup message is now suppressed in quiet mode.
  2025. X */
  2026. X
  2027. X
  2028. X
  2029. X
  2030. X#include "rcsbase.h"
  2031. X
  2032. libId(utilId, "$Id: rcsutil.c,v 5.10 1991/10/07 17:32:46 eggert Exp $")
  2033. X
  2034. X#if !has_memcmp
  2035. X    int
  2036. memcmp(s1, s2, n)
  2037. X    void const *s1, *s2;
  2038. X    size_t n;
  2039. X{
  2040. X    register unsigned char const
  2041. X        *p1 = (unsigned char const*)s1,
  2042. X        *p2 = (unsigned char const*)s2;
  2043. X    register size_t i = n;
  2044. X    register int r = 0;
  2045. X    while (i--  &&  !(r = (*p1++ - *p2++)))
  2046. X        ;
  2047. X    return r;
  2048. X}
  2049. X#endif
  2050. X
  2051. X#if !has_memcpy
  2052. X    void *
  2053. memcpy(s1, s2, n)
  2054. X    void *s1;
  2055. X    void const *s2;
  2056. X    size_t n;
  2057. X{
  2058. X    register char *p1 = (char*)s1;
  2059. X    register char const *p2 = (char const*)s2;
  2060. X    while (n--)
  2061. X        *p1++ = *p2++;
  2062. X    return s1;
  2063. X}
  2064. X#endif
  2065. X
  2066. X#if lint
  2067. X    malloc_type lintalloc;
  2068. X#endif
  2069. X
  2070. X/*
  2071. X * list of blocks allocated with ftestalloc()
  2072. X * These blocks can be freed by ffree when we're done with the current file.
  2073. X * We could put the free block inside struct alloclist, rather than a pointer
  2074. X * to the free block, but that would be less portable.
  2075. X */
  2076. struct alloclist {
  2077. X    malloc_type alloc;
  2078. X    struct alloclist *nextalloc;
  2079. X};
  2080. static struct alloclist *alloced;
  2081. X
  2082. X
  2083. X    static malloc_type
  2084. okalloc(p)
  2085. X    malloc_type p;
  2086. X{
  2087. X    if (!p)
  2088. X        faterror("out of memory");
  2089. X    return p;
  2090. X}
  2091. X
  2092. X    malloc_type
  2093. testalloc(size)
  2094. X    size_t size;
  2095. X/* Allocate a block, testing that the allocation succeeded.  */
  2096. X{
  2097. X    return okalloc(malloc(size));
  2098. X}
  2099. X
  2100. X    malloc_type
  2101. testrealloc(ptr, size)
  2102. X    malloc_type ptr;
  2103. X    size_t size;
  2104. X/* Reallocate a block, testing that the allocation succeeded.  */
  2105. X{
  2106. X    return okalloc(realloc(ptr, size));
  2107. X}
  2108. X
  2109. X    malloc_type
  2110. fremember(ptr)
  2111. X    malloc_type ptr;
  2112. X/* Remember PTR in 'alloced' so that it can be freed later.  Yield PTR.  */
  2113. X{
  2114. X    register struct alloclist *q = talloc(struct alloclist);
  2115. X    q->nextalloc = alloced;
  2116. X    alloced = q;
  2117. X    return q->alloc = ptr;
  2118. X}
  2119. X
  2120. X    malloc_type
  2121. ftestalloc(size)
  2122. X    size_t size;
  2123. X/* Allocate a block, putting it in 'alloced' so it can be freed later. */
  2124. X{
  2125. X    return fremember(testalloc(size));
  2126. X}
  2127. X
  2128. X    void
  2129. ffree()
  2130. X/* Free all blocks allocated with ftestalloc().  */
  2131. X{
  2132. X    register struct alloclist *p, *q;
  2133. X    for (p = alloced;  p;  p = q) {
  2134. X        q = p->nextalloc;
  2135. X        tfree(p->alloc);
  2136. X        tfree(p);
  2137. X    }
  2138. X    alloced = nil;
  2139. X}
  2140. X
  2141. X    void
  2142. ffree1(f)
  2143. X    register char const *f;
  2144. X/* Free the block f, which was allocated by ftestalloc.  */
  2145. X{
  2146. X    register struct alloclist *p, **a = &alloced;
  2147. X
  2148. X    while ((p = *a)->alloc  !=  f)
  2149. X        a = &p->nextalloc;
  2150. X    *a = p->nextalloc;
  2151. X    tfree(p->alloc);
  2152. X    tfree(p);
  2153. X}
  2154. X
  2155. X    char *
  2156. str_save(s)
  2157. X    char const *s;
  2158. X/* Save s in permanently allocated storage. */
  2159. X{
  2160. X    return strcpy(tnalloc(char, strlen(s)+1), s);
  2161. X}
  2162. X
  2163. X    char *
  2164. fstr_save(s)
  2165. X    char const *s;
  2166. X/* Save s in storage that will be deallocated when we're done with this file. */
  2167. X{
  2168. X    return strcpy(ftnalloc(char, strlen(s)+1), s);
  2169. X}
  2170. X
  2171. X    char *
  2172. cgetenv(name)
  2173. X    char const *name;
  2174. X/* Like getenv(), but yield a copy; getenv() can overwrite old results. */
  2175. X{
  2176. X    register char *p;
  2177. X
  2178. X    return (p=getenv(name)) ? str_save(p) : p;
  2179. X}
  2180. X
  2181. X    char const *
  2182. getusername(suspicious)
  2183. X    int suspicious;
  2184. X/* Get the caller's login name.  Trust only getwpuid if SUSPICIOUS.  */
  2185. X{
  2186. X    static char *name;
  2187. X
  2188. X    if (!name) {
  2189. X        if (
  2190. X            /* Prefer getenv() unless suspicious; it's much faster.  */
  2191. X#            if getlogin_is_secure
  2192. X                (suspicious
  2193. X                ||
  2194. X                !(name = cgetenv("LOGNAME"))
  2195. X                &&  !(name = cgetenv("USER")))
  2196. X            &&  !(name = getlogin())
  2197. X#            else
  2198. X            suspicious
  2199. X            ||
  2200. X                !(name = cgetenv("LOGNAME"))
  2201. X                &&  !(name = cgetenv("USER"))
  2202. X                &&  !(name = getlogin())
  2203. X#            endif
  2204. X        ) {
  2205. X#if has_getuid && has_getpwuid
  2206. X            struct passwd const *pw = getpwuid(ruid());
  2207. X            if (!pw)
  2208. X                faterror("no password entry for userid %lu",
  2209. X                     (unsigned long)ruid()
  2210. X                );
  2211. X            name = pw->pw_name;
  2212. X#else
  2213. X#if has_setuid
  2214. X            faterror("setuid not supported");
  2215. X#else
  2216. X            faterror("Who are you?  Please set LOGNAME.");
  2217. X#endif
  2218. X#endif
  2219. X        }
  2220. X        checksid(name);
  2221. X    }
  2222. X    return name;
  2223. X}
  2224. X
  2225. X
  2226. X
  2227. X
  2228. X#if has_signal
  2229. X
  2230. X/*
  2231. X *     Signal handling
  2232. X *
  2233. X * Standard C places too many restrictions on signal handlers.
  2234. X * We obey as many of them as we can.
  2235. X * Posix places fewer restrictions, and we are Posix-compatible here.
  2236. X */
  2237. X
  2238. static sig_atomic_t volatile heldsignal, holdlevel;
  2239. X
  2240. X    static signal_type
  2241. catchsig(s)
  2242. X    int s;
  2243. X{
  2244. X    char const *sname;
  2245. X    char buf[BUFSIZ];
  2246. X
  2247. X#if sig_zaps_handler
  2248. X    /* If a signal arrives before we reset the signal handler, we lose. */
  2249. X    VOID signal(s, SIG_IGN);
  2250. X#endif
  2251. X    if (holdlevel) {
  2252. X        heldsignal = s;
  2253. X        return;
  2254. X    }
  2255. X    ignoreints();
  2256. X    setrid();
  2257. X    if (!quietflag) {
  2258. X        sname = nil;
  2259. X#if has_sys_siglist && defined(NSIG)
  2260. X        if ((unsigned)s < NSIG) {
  2261. X#        ifndef sys_siglist
  2262. X            extern char const *sys_siglist[];
  2263. X#        endif
  2264. X        sname = sys_siglist[s];
  2265. X        }
  2266. X#else
  2267. X        switch (s) {
  2268. X#ifdef SIGHUP
  2269. X        case SIGHUP:    sname = "Hangup";  break;
  2270. X#endif
  2271. X#ifdef SIGINT
  2272. X        case SIGINT:    sname = "Interrupt";  break;
  2273. X#endif
  2274. X#ifdef SIGPIPE
  2275. X        case SIGPIPE:    sname = "Broken pipe";  break;
  2276. X#endif
  2277. X#ifdef SIGQUIT
  2278. X        case SIGQUIT:    sname = "Quit";  break;
  2279. X#endif
  2280. X#ifdef SIGTERM
  2281. X        case SIGTERM:    sname = "Terminated";  break;
  2282. X#endif
  2283. X#ifdef SIGXCPU
  2284. X        case SIGXCPU:    sname = "Cputime limit exceeded";  break;
  2285. X#endif
  2286. X#ifdef SIGXFSZ
  2287. X        case SIGXFSZ:    sname = "Filesize limit exceeded";  break;
  2288. X#endif
  2289. X        }
  2290. X#endif
  2291. X        if (sname)
  2292. X        VOID sprintf(buf, "\nRCS: %s.  Cleaning up.\n", sname);
  2293. X        else
  2294. X        VOID sprintf(buf, "\nRCS: Signal %d.  Cleaning up.\n", s);
  2295. X        VOID write(STDERR_FILENO, buf, strlen(buf));
  2296. X    }
  2297. X    exiterr();
  2298. X}
  2299. X
  2300. X    void
  2301. ignoreints()
  2302. X{
  2303. X    ++holdlevel;
  2304. X}
  2305. X
  2306. X    void
  2307. restoreints()
  2308. X{
  2309. X    if (!--holdlevel && heldsignal)
  2310. X        VOID catchsig(heldsignal);
  2311. X}
  2312. X
  2313. X
  2314. static int const sig[] = {
  2315. X#ifdef SIGHUP
  2316. X    SIGHUP,
  2317. X#endif
  2318. X#ifdef SIGINT
  2319. X    SIGINT,
  2320. X#endif
  2321. X#ifdef SIGPIPE
  2322. X    SIGPIPE,
  2323. X#endif
  2324. X#ifdef SIGQUIT
  2325. X    SIGQUIT,
  2326. X#endif
  2327. X#ifdef SIGTERM
  2328. X    SIGTERM,
  2329. X#endif
  2330. X#ifdef SIGXCPU
  2331. X    SIGXCPU,
  2332. X#endif
  2333. X#ifdef SIGXFSZ
  2334. X    SIGXFSZ,
  2335. X#endif
  2336. X};
  2337. X#define SIGS (sizeof(sig)/sizeof(*sig))
  2338. X
  2339. X
  2340. X#if has_sigaction
  2341. X
  2342. X    static void
  2343. X  check_sig(r)
  2344. X    int r;
  2345. X  {
  2346. X    if (r != 0)
  2347. X        efaterror("signal");
  2348. X  }
  2349. X
  2350. X    static void
  2351. X  setup_catchsig()
  2352. X  {
  2353. X    register int i;
  2354. X    sigset_t blocked;
  2355. X    struct sigaction act;
  2356. X
  2357. X    check_sig(sigemptyset(&blocked));
  2358. X    for (i=SIGS; 0<=--i; )
  2359. X        check_sig(sigaddset(&blocked, sig[i]));
  2360. X    for (i=SIGS; 0<=--i; ) {
  2361. X        check_sig(sigaction(sig[i], (struct sigaction*)nil, &act));
  2362. X        if (act.sa_handler != SIG_IGN) {
  2363. X            act.sa_handler = catchsig;
  2364. X            act.sa_mask = blocked;
  2365. X            check_sig(sigaction(sig[i], &act, (struct sigaction*)nil));
  2366. X        }
  2367. X    }
  2368. X  }
  2369. X
  2370. X#else
  2371. X#if has_sigblock
  2372. X
  2373. X    static void
  2374. X  setup_catchsig()
  2375. X  {
  2376. X    register int i;
  2377. X    int mask;
  2378. X
  2379. X    mask = 0;
  2380. X    for (i=SIGS; 0<=--i; )
  2381. X        mask |= sigmask(sig[i]);
  2382. X    mask = sigblock(mask);
  2383. X    for (i=SIGS; 0<=--i; )
  2384. X        if (
  2385. X            signal(sig[i], catchsig) == SIG_IGN  &&
  2386. X            signal(sig[i], SIG_IGN) != catchsig
  2387. X        )
  2388. X            faterror("signal catcher failure");
  2389. X    VOID sigsetmask(mask);
  2390. X  }
  2391. X
  2392. X#else
  2393. X
  2394. X    static void
  2395. X  setup_catchsig()
  2396. X  {
  2397. X    register i;
  2398. X
  2399. X    for (i=SIGS; 0<=--i; )
  2400. X        if (
  2401. X            signal(sig[i], SIG_IGN) != SIG_IGN  &&
  2402. X            signal(sig[i], catchsig) != SIG_IGN
  2403. X        )
  2404. X            faterror("signal catcher failure");
  2405. X  }
  2406. X
  2407. X#endif
  2408. X#endif
  2409. X
  2410. X    void
  2411. catchints()
  2412. X{
  2413. X    static int catching_ints;
  2414. X    if (!catching_ints) {
  2415. X        catching_ints = true;
  2416. X        setup_catchsig();
  2417. X    }
  2418. X}
  2419. X
  2420. X#endif /* has_signal */
  2421. X
  2422. X
  2423. X    void
  2424. fastcopy(inf,outf)
  2425. X    register RILE *inf;
  2426. X    FILE *outf;
  2427. X/* Function: copies the remainder of file inf to outf.
  2428. X */
  2429. X{
  2430. X#if large_memory
  2431. X#    if has_mmap
  2432. X        awrite((char const*)inf->ptr, (size_t)(inf->lim - inf->ptr), outf);
  2433. X        inf->ptr = inf->lim;
  2434. X#    else
  2435. X        for (;;) {
  2436. X        awrite((char const*)inf->ptr, (size_t)(inf->readlim - inf->ptr), outf);
  2437. X        inf->ptr = inf->readlim;
  2438. X        if (inf->ptr == inf->lim)
  2439. X            break;
  2440. X        VOID Igetmore(inf);
  2441. X        }
  2442. X#    endif
  2443. X#else
  2444. X    char buf[BUFSIZ*8];
  2445. X    register fread_type rcount;
  2446. X
  2447. X        /*now read the rest of the file in blocks*/
  2448. X    while (!feof(inf)) {
  2449. X        if (!(rcount = Fread(buf,sizeof(*buf),sizeof(buf),inf))) {
  2450. X            testIerror(inf);
  2451. X            return;
  2452. X        }
  2453. X        awrite(buf, (size_t)rcount, outf);
  2454. X        }
  2455. X#endif
  2456. X}
  2457. X
  2458. X#ifndef SSIZE_MAX
  2459. X /* This does not work in #ifs, but it's good enough for us.  */
  2460. X /* Underestimating SSIZE_MAX may slow us down, but it won't break us.  */
  2461. X#    define SSIZE_MAX ((unsigned)-1 >> 1)
  2462. X#endif
  2463. X
  2464. X    void
  2465. awrite(buf, chars, f)
  2466. X    char const *buf;
  2467. X    size_t chars;
  2468. X    FILE *f;
  2469. X{
  2470. X    /* Posix 1003.1-1990 ssize_t hack */
  2471. X    while (SSIZE_MAX < chars) {
  2472. X        if (Fwrite(buf, sizeof(*buf), SSIZE_MAX, f)  !=  SSIZE_MAX)
  2473. X            Oerror();
  2474. X        buf += SSIZE_MAX;
  2475. X        chars -= SSIZE_MAX;
  2476. X    }
  2477. X
  2478. X    if (Fwrite(buf, sizeof(*buf), chars, f)  !=  chars)
  2479. X        Oerror();
  2480. X}
  2481. X
  2482. X
  2483. X
  2484. X
  2485. X
  2486. X    static int
  2487. movefd(old, new)
  2488. X    int old, new;
  2489. X{
  2490. X    if (old < 0  ||  old == new)
  2491. X        return old;
  2492. X#    ifdef F_DUPFD
  2493. X        new = fcntl(old, F_DUPFD, new);
  2494. X#    else
  2495. X        new = dup2(old, new);
  2496. X#    endif
  2497. X    return close(old)==0 ? new : -1;
  2498. X}
  2499. X
  2500. X    static int
  2501. fdreopen(fd, file, flags)
  2502. X    int fd;
  2503. X    char const *file;
  2504. X    int flags;
  2505. X{
  2506. X    int newfd;
  2507. X    VOID close(fd);
  2508. X    newfd =
  2509. X#if !open_can_creat
  2510. X        flags&O_CREAT ? creat(file, S_IRUSR|S_IWUSR) :
  2511. X#endif
  2512. X        open(file, flags, S_IRUSR|S_IWUSR);
  2513. X    return movefd(newfd, fd);
  2514. X}
  2515. X
  2516. X#if !has_spawn
  2517. X    static void
  2518. tryopen(fd,file,flags)
  2519. X    int fd, flags;
  2520. X    char const *file;
  2521. X{
  2522. X    if (file  &&  fdreopen(fd,file,flags) != fd)
  2523. X        efaterror(file);
  2524. X}
  2525. X#else
  2526. X    static int
  2527. tryopen(fd,file,flags)
  2528. X    int fd, flags;
  2529. X    char const *file;
  2530. X{
  2531. X    int newfd = -1;
  2532. X    if (file  &&  ((newfd=dup(fd)) < 0  ||  fdreopen(fd,file,flags) != fd))
  2533. X        efaterror(file);
  2534. X    return newfd;
  2535. X}
  2536. X    static void
  2537. redirect(old, new)
  2538. X    int old, new;
  2539. X{
  2540. X    if (0 <= old   &&   (close(new) != 0  ||  movefd(old,new) < 0))
  2541. X        efaterror("spawn I/O redirection");
  2542. X}
  2543. X#endif
  2544. X
  2545. X
  2546. X
  2547. X#if !has_fork && !has_spawn
  2548. X    static void
  2549. bufargcat(b, c, s)
  2550. X    register struct buf *b;
  2551. X    int c;
  2552. X    register char const *s;
  2553. X/* Append to B a copy of C, plus a quoted copy of S.  */
  2554. X{
  2555. X    register char *p;
  2556. X    register char const *t;
  2557. X    size_t bl, sl;
  2558. X
  2559. X    for (t=s, sl=0;  *t;  )
  2560. X        sl  +=  3*(*t++=='\'') + 1;
  2561. X    bl = strlen(b->string);
  2562. X    bufrealloc(b, bl + sl + 4);
  2563. X    p = b->string + bl;
  2564. X    *p++ = c;
  2565. X    *p++ = '\'';
  2566. X    while (*s) {
  2567. X        if (*s == '\'') {
  2568. X            *p++ = '\'';
  2569. X            *p++ = '\\';
  2570. X            *p++ = '\'';
  2571. X        }
  2572. X        *p++ = *s++;
  2573. X    }
  2574. X    *p++ = '\'';
  2575. X    *p = 0;
  2576. X}
  2577. X#endif
  2578. X
  2579. X/*
  2580. X* Run a command specified by the strings in 'inoutargs'.
  2581. X* inoutargs[0], if nonnil, is the name of the input file.
  2582. X* inoutargs[1], if nonnil, is the name of the output file.
  2583. X* inoutargs[2..] form the command to be run.
  2584. X*/
  2585. X    int
  2586. runv(inoutargs)
  2587. X    char const **inoutargs;
  2588. X{
  2589. X    register char const **p;
  2590. X    int wstatus;
  2591. X
  2592. X    oflush();
  2593. X    eflush();
  2594. X    {
  2595. X#if has_spawn
  2596. X    int in, out;
  2597. X    p = inoutargs;
  2598. X    in = tryopen(STDIN_FILENO, *p++, O_BINARY|O_RDONLY);
  2599. X    out = tryopen(STDOUT_FILENO, *p++, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY);
  2600. X    wstatus = spawn_RCS(0, *p, (char*const*)p);
  2601. X    if (wstatus == -1  &&  errno == ENOEXEC) {
  2602. X        *--p = RCS_SHELL;
  2603. X        wstatus = spawnv(0, *p, (char*const*)p);
  2604. X    }
  2605. X    redirect(in, STDIN_FILENO);
  2606. X    redirect(out, STDOUT_FILENO);
  2607. X#else
  2608. X#if has_fork
  2609. X    pid_t pid;
  2610. X#    if !has_waitpid
  2611. X        pid_t w;
  2612. X#    endif
  2613. X    if (!(pid = vfork())) {
  2614. X        p = inoutargs;
  2615. X        tryopen(STDIN_FILENO, *p++, O_BINARY|O_RDONLY);
  2616. X        tryopen(STDOUT_FILENO, *p++, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY);
  2617. X        VOID exec_RCS(*p, (char*const*)p);
  2618. X        if (errno == ENOEXEC) {
  2619. X            *--p = RCS_SHELL;
  2620. X            VOID execv(*p, (char*const*)p);
  2621. X        }
  2622. X        VOID write(STDERR_FILENO, *p, strlen(*p));
  2623. X        VOID write(STDERR_FILENO, ": not found\n", 12);
  2624. X        _exit(EXIT_TROUBLE);
  2625. X    }
  2626. X    if (pid < 0)
  2627. X        efaterror("fork");
  2628. X#    if has_waitpid
  2629. X        if (waitpid(pid, &wstatus, 0) < 0)
  2630. X            efaterror("waitpid");
  2631. X#    else
  2632. X        do {
  2633. X            if ((w = wait(&wstatus)) < 0)
  2634. X                efaterror("wait");
  2635. X        } while (w != pid);
  2636. X#    endif
  2637. X#else
  2638. X    static struct buf b;
  2639. X
  2640. X    /* Use system().  On many hosts system() discards signals.  Yuck!  */
  2641. X    p = inoutargs+2;
  2642. X    bufscpy(&b, *p);
  2643. X    while (*++p)
  2644. X        bufargcat(&b, ' ', *p);
  2645. X    if (inoutargs[0])
  2646. X        bufargcat(&b, '<', inoutargs[0]);
  2647. X    if (inoutargs[1])
  2648. X        bufargcat(&b, '>', inoutargs[1]);
  2649. X    wstatus = system(b.string);
  2650. X#endif
  2651. X#endif
  2652. X    }
  2653. X    if (!WIFEXITED(wstatus))
  2654. X        faterror("%s failed", inoutargs[2]);
  2655. X    return WEXITSTATUS(wstatus);
  2656. X}
  2657. X
  2658. X#define CARGSMAX 20
  2659. X/*
  2660. X* Run a command.
  2661. X* The first two arguments are the input and output files (if nonnil);
  2662. X* the rest specify the command and its arguments.
  2663. X*/
  2664. X    int
  2665. X#if has_prototypes
  2666. run(char const *infile, char const *outfile, ...)
  2667. X#else
  2668. X    /*VARARGS2*/
  2669. run(infile, outfile, va_alist)
  2670. X    char const *infile;
  2671. X    char const *outfile;
  2672. X    va_dcl
  2673. X#endif
  2674. X{
  2675. X    va_list ap;
  2676. X    char const *rgargs[CARGSMAX];
  2677. X    register i = 0;
  2678. X    rgargs[0] = infile;
  2679. X    rgargs[1] = outfile;
  2680. X    vararg_start(ap, outfile);
  2681. X    for (i = 2;  (rgargs[i++] = va_arg(ap, char const*));  )
  2682. X        if (CARGSMAX <= i)
  2683. X            faterror("too many command arguments");
  2684. X    va_end(ap);
  2685. X    return runv(rgargs);
  2686. X}
  2687. X
  2688. X
  2689. X    char const *
  2690. date2str(date, datebuf)
  2691. X    char const date[datesize];
  2692. X    char datebuf[datesize];
  2693. X/*
  2694. X* Format a user-readable form of the RCS format DATE into the buffer DATEBUF.
  2695. X* Yield DATEBUF.
  2696. X*/
  2697. X{
  2698. X    register char const *p = date;
  2699. X
  2700. X    while (*p++ != '.')
  2701. X        ;
  2702. X    VOID sprintf(datebuf,
  2703. X        "19%.*s/%.2s/%.2s %.2s:%.2s:%s" +
  2704. X            (date[2]=='.' && VERSION(5)<=RCSversion  ?  0  :  2),
  2705. X        (int)(p-date-1), date,
  2706. X        p, p+3, p+6, p+9, p+12
  2707. X    );
  2708. X    return datebuf;
  2709. X}
  2710. X
  2711. X
  2712. int RCSversion;
  2713. X
  2714. X    void
  2715. setRCSversion(str)
  2716. X    char const *str;
  2717. X{
  2718. X    static int oldversion;
  2719. X
  2720. X    register char const *s = str + 2;
  2721. X    int v = VERSION_DEFAULT;
  2722. X
  2723. X    if (oldversion)
  2724. X        redefined('V');
  2725. X    oldversion = true;
  2726. X
  2727. X    if (*s) {
  2728. X        v = 0;
  2729. X        while (isdigit(*s))
  2730. X            v  =  10*v + *s++ - '0';
  2731. X        if (*s)
  2732. X            faterror("%s isn't a number", str);
  2733. X        if (v < VERSION_min  ||  VERSION_max < v)
  2734. X            faterror("%s out of range %d..%d", str, VERSION_min, VERSION_max);
  2735. X    }
  2736. X
  2737. X    RCSversion = VERSION(v);
  2738. X}
  2739. X
  2740. X    int
  2741. getRCSINIT(argc, argv, newargv)
  2742. X    int argc;
  2743. X    char **argv, ***newargv;
  2744. X{
  2745. X    register char *p, *q, **pp;
  2746. X    unsigned n;
  2747. X
  2748. X    if (!(q = cgetenv("RCSINIT")))
  2749. X        *newargv = argv;
  2750. X    else {
  2751. X        n = argc + 2;
  2752. X        /*
  2753. X         * Count spaces in RCSINIT to allocate a new arg vector.
  2754. X         * This is an upper bound, but it's OK even if too large.
  2755. X         */
  2756. X        for (p = q;  ;  ) {
  2757. X            switch (*p++) {
  2758. X                default:
  2759. X                continue;
  2760. X
  2761. X                case ' ':
  2762. X                case '\b': case '\f': case '\n':
  2763. X                case '\r': case '\t': case '\v':
  2764. X                n++;
  2765. X                continue;
  2766. X
  2767. X                case '\0':
  2768. X                break;
  2769. X            }
  2770. X            break;
  2771. X        }
  2772. X        *newargv = pp = tnalloc(char*, n);
  2773. X        *pp++ = *argv++; /* copy program name */
  2774. X        for (p = q;  ;  ) {
  2775. X            for (;;) {
  2776. X                switch (*q) {
  2777. X                    case '\0':
  2778. X                    goto copyrest;
  2779. X
  2780. X                    case ' ':
  2781. X                    case '\b': case '\f': case '\n':
  2782. X                    case '\r': case '\t': case '\v':
  2783. X                    q++;
  2784. X                    continue;
  2785. X                }
  2786. X                break;
  2787. X            }
  2788. X            *pp++ = p;
  2789. X            ++argc;
  2790. X            for (;;) {
  2791. X                switch ((*p++ = *q++)) {
  2792. X                    case '\0':
  2793. X                    goto copyrest;
  2794. X
  2795. X                    case '\\':
  2796. X                    if (!*q)
  2797. X                        goto copyrest;
  2798. X                    p[-1] = *q++;
  2799. X                    continue;
  2800. X
  2801. X                    default:
  2802. X                    continue;
  2803. X
  2804. X                    case ' ':
  2805. X                    case '\b': case '\f': case '\n':
  2806. X                    case '\r': case '\t': case '\v':
  2807. X                    break;
  2808. X                }
  2809. X                break;
  2810. X            }
  2811. X            p[-1] = '\0';
  2812. X        }
  2813. X        copyrest:
  2814. X        while ((*pp++ = *argv++))
  2815. X            ;
  2816. X    }
  2817. X    return argc;
  2818. X}
  2819. X
  2820. X
  2821. X#define cacheid(E) static uid_t i; static int s; if (!s){ s=1; i=(E); } return i
  2822. X
  2823. X#if has_getuid
  2824. X    uid_t ruid() { cacheid(getuid()); }
  2825. X#endif
  2826. X#if has_setuid
  2827. X    uid_t euid() { cacheid(geteuid()); }
  2828. X#endif
  2829. X
  2830. X
  2831. X#if has_setuid
  2832. X
  2833. X/*
  2834. X * Setuid execution really works only with Posix 1003.1a Draft 5 seteuid(),
  2835. X * because it lets us switch back and forth between arbitrary users.
  2836. X * If seteuid() doesn't work, we fall back on setuid(),
  2837. X * which works if saved setuid is supported,
  2838. X * unless the real or effective user is root.
  2839. X * This area is such a mess that we always check switches at runtime.
  2840. X */
  2841. X
  2842. X    static void
  2843. set_uid_to(u)
  2844. X    uid_t u;
  2845. X/* Become user u.  */
  2846. X{
  2847. X    static int looping;
  2848. X
  2849. X    if (euid() == ruid())
  2850. X        return;
  2851. X#if (has_fork||has_spawn) && DIFF_ABSOLUTE
  2852. X    if (seteuid(u) != 0)
  2853. X        efaterror("setuid");
  2854. X#endif
  2855. X    if (geteuid() != u) {
  2856. X        if (looping)
  2857. X            return;
  2858. X        looping = true;
  2859. X        faterror("root setuid not supported" + (u?5:0));
  2860. X    }
  2861. X}
  2862. X
  2863. static int stick_with_euid;
  2864. X
  2865. X    void
  2866. X/* Ignore all calls to seteid() and setrid().  */
  2867. nosetid()
  2868. X{
  2869. X    stick_with_euid = true;
  2870. X}
  2871. X
  2872. X    void
  2873. seteid()
  2874. X/* Become effective user.  */
  2875. X{
  2876. X    if (!stick_with_euid)
  2877. X        set_uid_to(euid());
  2878. X}
  2879. X
  2880. X    void
  2881. setrid()
  2882. X/* Become real user.  */
  2883. X{
  2884. X    if (!stick_with_euid)
  2885. X        set_uid_to(ruid());
  2886. X}
  2887. X#endif
  2888. END_OF_FILE
  2889. if test 20392 -ne `wc -c <'src/rcsutil.c'`; then
  2890.     echo shar: \"'src/rcsutil.c'\" unpacked with wrong size!
  2891. fi
  2892. # end of 'src/rcsutil.c'
  2893. fi
  2894. echo shar: End of archive 4 \(of 11\).
  2895. cp /dev/null ark4isdone
  2896. MISSING=""
  2897. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  2898.     if test ! -f ark${I}isdone ; then
  2899.     MISSING="${MISSING} ${I}"
  2900.     fi
  2901. done
  2902. if test "${MISSING}" = "" ; then
  2903.     echo You have unpacked all 11 archives.
  2904.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2905. else
  2906.     echo You still need to unpack the following archives:
  2907.     echo "        " ${MISSING}
  2908. fi
  2909. ##  End of shell archive.
  2910. exit 0
  2911.