1 /* RCS common definitions and data structures
2 
3    Copyright (C) 2010-2020 Thien-Thi Nguyen
4    Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
5    Copyright (C) 1982, 1988, 1989 Walter Tichy
6 
7    This file is part of GNU RCS.
8 
9    GNU RCS is free software: you can redistribute it and/or modify it
10    under the terms of the GNU General Public License as published by
11    the Free Software Foundation, either version 3 of the License, or
12    (at your option) any later version.
13 
14    GNU RCS is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty
16    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17    See the GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22 
23 #include "config.h"
24 #include <stdbool.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include "vla.h"
30 
31 #ifdef HAVE_LIMITS_H
32 #include <limits.h>
33 #endif
34 #ifdef HAVE_MACH_MACH_H
35 #include <mach/mach.h>
36 #endif
37 #ifdef HAVE_NET_ERRNO_H
38 #include <net/errno.h>
39 #endif
40 #ifdef HAVE_VFORK_H
41 #include <vfork.h>
42 #endif
43 
44 #define exiting  _Noreturn
45 
46 /* Some compilers, notably:
47    - IBM XL C/C++ for AIX, V11.1 (5724-X13), Version: 11.01.0000.0019
48    don't like implicitly considering non-‘NULL’ pointers as ‘true’.  */
49 #define BOOLEAN(x)  ((x) ? true : false)
50 
51 /* GCC attributes  */
52 
53 #define ARG_NONNULL(which)  _GL_ARG_NONNULL (which)
54 #define ALL_NONNULL         _GL_ARG_NONNULL ()
55 
56 #define RCS_UNUSED  _GL_UNUSED
57 
58 #if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
59 #define printf_string(m, n)  __attribute__ ((__format__ (printf, m, n)))
60 #else
61 #define printf_string(m, n)
62 #endif
63 
64 /* Keyword substitution modes.  The order must agree with ‘kwsub_pool’.  */
65 enum kwsub
66   {
67     kwsub_kv,                           /* $Keyword: value $ */
68     kwsub_kvl,                          /* $Keyword: value locker $ */
69     kwsub_k,                            /* $Keyword$ */
70     kwsub_v,                            /* value */
71     kwsub_o,                            /* (old string) */
72     kwsub_b                             /* (binary i/o old string) */
73   };
74 
75 /* begin cruft formerly from from conf.h */
76 
77 #ifdef O_BINARY
78 /* Text and binary i/o behave differently.
79    This is incompatible with POSIX and Unix.  */
80 #define FOPEN_RB "rb"
81 #define FOPEN_R_WORK (BE (kws) == kwsub_b ? "r" : "rb")
82 #define FOPEN_WB "wb"
83 #define FOPEN_W_WORK (BE (kws) == kwsub_b ? "w" : "wb")
84 #define FOPEN_WPLUS_WORK (BE (kws) == kwsub_b ? "w+" : "w+b")
85 #define OPEN_O_BINARY O_BINARY
86 #else
87 /* Text and binary i/o behave the same.
88    Omit "b", since some nonstandard hosts reject it. */
89 #define FOPEN_RB "r"
90 #define FOPEN_R_WORK "r"
91 #define FOPEN_WB "w"
92 #define FOPEN_W_WORK "w"
93 #define FOPEN_WPLUS_WORK "w+"
94 #define OPEN_O_BINARY 0
95 #endif
96 
97 /* Lock file mode.  */
98 #define OPEN_CREAT_READONLY (S_IRUSR|S_IRGRP|S_IROTH)
99 
100 /* Extra open flags for creating lock file.  */
101 #define OPEN_O_LOCK 0
102 
103 /* Main open flag for creating a lock file.  */
104 #define OPEN_O_WRONLY O_WRONLY
105 
106 /* Can ‘rename (A, B)’ falsely report success?  */
107 #define bad_NFS_rename 0
108 
109 /* Might NFS be used?  */
110 #define has_NFS 1
111 
112 /* Shell to run RCS subprograms.  */
113 #define RCS_SHELL "/bin/sh"
114 
115 /* Filename component separation.
116    TMPDIR       string           Default directory for temporary files.
117    SLASH        char             Principal filename separator.
118    SLASHes      ‘case SLASHes:’  Labels all filename separators.
119    ABSFNAME(p)  expression       Is p an absolute filename?
120 */
121 #if !WOE
122 #define TMPDIR "/tmp"
123 #define SLASH '/'
124 #define SLASHes '/'
125 #define ABSFNAME(p)  (isSLASH ((p)[0]))
126 #else /* WOE */
127 #define TMPDIR "\\tmp"
128 #define SLASH "'\\'"
129 #define SLASHes '\\': case '/': case ':'
130 #define ABSFNAME(p)  (isSLASH ((p)[0]) || (p)[0] && (p)[1] == ':')
131 #endif
132 
133 /* Must TZ be set for ‘gmtime_r’ to work?  */
134 #define TZ_must_be_set 0
135 
136 #if defined HAVE_WORKING_FORK && !defined HAVE_WORKING_VFORK
137 #undef vfork
138 #define vfork fork
139 #endif
140 
141 /* end cruft formerly from from conf.h */
142 
143 #ifdef _POSIX_PATH_MAX
144 #define SIZEABLE_FILENAME_LEN  _POSIX_PATH_MAX
145 #else
146 /* Size of a large filename; not a hard limit.  */
147 #define SIZEABLE_FILENAME_LEN  255
148 #endif
149 
150 /* Backwards compatibility with old versions of RCS.  */
151 
152 /* Oldest output RCS format supported.  */
153 #define VERSION_min 3
154 /* Newest output RCS format supported. */
155 #define VERSION_max 5
156 /* Default RCS output format.  */
157 #ifndef VERSION_DEFAULT
158 #define VERSION_DEFAULT VERSION_max
159 #endif
160 /* Internally, 0 is the default.  */
161 #define VERSION(n)  ((n) - VERSION_DEFAULT)
162 
163 /* Locking strictness
164    false sets the default locking to non-strict;
165    used in experimental environments.
166    true sets the default locking to strict;
167    used in production environments.
168 */
169 #ifndef STRICT_LOCKING
170 #define STRICT_LOCKING  true
171 #endif
172 
173 /* Delimiter for keywords.  */
174 #define KDELIM                               '$'
175 /* Separates keywords from values.  */
176 #define VDELIM                               ':'
177 /* Default state of revisions.  */
178 #define DEFAULTSTATE                         "Exp"
179 
180 /* Minimum value for no logical expansion.  */
181 #define MIN_UNEXPAND  kwsub_o
182 /* The minimum value guaranteed to yield an identical file.  */
183 #define MIN_UNCHANGED_EXPAND  (OPEN_O_BINARY ? kwsub_b : kwsub_o)
184 
185 /* Define to 1 to enable the "need expansion" handling
186    (support for a future rewrite of b-kwxout).  */
187 #define WITH_NEEDEXP 0
188 
189 struct diffcmd
190 {
191   /* Number of first line.  */
192   long line1;
193   /* Number of lines affected.  */
194   long nlines;
195   /* Previous 'a' line1+1 or 'd' line1.  */
196   long adprev;
197   /* Sum of previous 'd' line1 and previous 'd' nlines.  */
198   long dafter;
199 };
200 
201 /* If there is no signal, better to disable mmap entirely.
202    We leave MMAP_SIGNAL as 0 to indicate this.  */
203 #if !MMAP_SIGNAL
204 #undef HAVE_MMAP
205 #undef HAVE_MADVISE
206 #endif
207 
208 /* Print a char, but abort on write error.  */
209 #define aputc(c,o)  do                          \
210     if (putc (c, o) == EOF)                     \
211       testOerror (o);                           \
212   while (0)
213 
214 /* Computes mode of the working file: same as ‘RCSmode’,
215    but write permission determined by ‘writable’.  */
216 #define WORKMODE(RCSmode, writable)                     \
217   (((RCSmode) & (mode_t)~(S_IWUSR|S_IWGRP|S_IWOTH))     \
218    | ((writable) ? S_IWUSR : 0))
219 
220 /* Character classes and token codes.  */
221 enum tokens
222 {
223   /* Classes.  */
224   DELIM, DIGIT, IDCHAR, NEWLN, LETTER, Letter,
225   PERIOD, SBEGIN, SPACE, UNKN,
226   /* Tokens.  */
227   COLON, ID, NUM, SEMI, STRING
228 };
229 
230 /* The actual character is needed for string handling.
231    ‘SDELIM’ must be consistent with ‘ctab’, so that ‘ctab[SDELIM] == SBEGIN’.
232    There should be no overlap among ‘SDELIM’, ‘KDELIM’ and ‘VDELIM’.  */
233 #define SDELIM  '@'
234 
235 /* Data structures for the symbol table.  */
236 
237 struct cbuf                             /* immutable */
238 {
239   char const *string;
240   size_t size;
241 };
242 
243 /* A revision.  */
244 struct delta
245 {
246   /* Pointer to revision number (ASCIZ).  */
247   char const *num;
248 
249   /* Pointer to date of checkin, person checking in, the locker.  */
250   char const *date;
251   char const *author;
252   char const *lockedby;
253 
254   /* State of revision (see ‘DEFAULTSTATE’).  */
255   char const *state;
256 
257   /* The ‘log’ and ‘text’ fields.  */
258   struct atat *log, *text;
259 
260   /* Name (if any) by which retrieved.  */
261   char const *name;
262 
263   /* Log message requested at checkin.  */
264   struct cbuf pretty_log;
265 
266   /* List of ‘struct delta’ (first revisions) on branches.  */
267   struct wlink *branches;
268 
269   /* The ‘commitid’ added by CVS; only used for reading.  */
270   char const *commitid;
271 
272   /* Another revision on same branch.
273      This used to be named ‘next’, but that's confusing to me.  */
274   struct delta *ilk;
275 
276   /* True if selected, false if deleted.  */
277   bool selector;
278 
279   /* Position in ‘FLOW (from)’ of the start of the delta body,
280      including the leading whitespace, starting at the ‘ATAT_TEXT_END’
281      of the preceding description (desc) or delta body (text) atat.
282      Thus, the full backing store range of delta ‘d’ is ‘d.prologue’
283      up to ‘ATAT_TEXT_END (d.text)’.  */
284   off_t neck;
285 };
286 
287 /* List element for locks.  */
288 struct rcslock
289 {
290   char const *login;
291   struct delta *delta;
292 };
293 
294 /* List element for symbolic names.
295    Also used for label/filename (merging)
296    and base/full (peer program names).  */
297 struct symdef
298 {
299   char const *meaningful;
300   char const *underlying;
301 };
302 
303 /* Like ‘struct symdef’, for ci(1) and rcs(1).
304    The "u_" prefix stands for user-setting.  */
305 struct u_symdef
306 {
307   struct symdef u;
308   bool override;
309 };
310 
311 /* Symbol-pool particulars.  */
312 struct tinysym
313 {
314   uint8_t len;
315   uint8_t bytes[];
316 };
317 struct pool_found
318 {
319   int i;
320   struct tinysym const *sym;
321 };
322 
323 #define TINY(x)       (tiny_ ## x)
324 #define TINY_DECL(x)  const struct tinysym (TINY (x))
325 
326 /* Max length of the (working file) keywords.  */
327 #define keylength 8
328 
329 /* This must be in the same order as in ‘keyword_pool’.  */
330 enum markers
331 {
332   Author, Date, Header, Id,
333   Locker, Log, Name, RCSfile, Revision, Source, State
334 };
335 
336 /* This is used by ci and rlog.  */
337 #define EMPTYLOG "*** empty log message ***"
338 
339 /* Buffer sizes for time/date funcs.
340    The six is for the year, good through AD 999,999.
341    (This was chosen so that ‘FULLDATESIZE’ + 1 = 32.)
342    The second is basically ‘(1+ (length ".MM.DD.HH.MM.SS"))’.
343    9 is max len of time zone string, e.g. "+12:34:56".  */
344 #define DATESIZE            (6 + 16)
345 #define FULLDATESIZE        (DATESIZE + 9)
346 
347 struct maybe;
348 
349 /* The function ‘pairnames’ takes to open the RCS file.  */
350 typedef struct fro * (open_rcsfile_fn) (struct maybe *m);
351 
352 /* A combination of probe parameters and results for ‘pairnames’ through
353    ‘fin2open’ through ‘finopen’ through {‘rcsreadopen’, ‘rcswriteopen’}
354    (and ‘naturalize’ in the case of ‘rcswriteopen’).
355 
356    The probe protocol is to set ‘open’ and ‘mustread’ once, and try various
357    permutations of basename, directory and extension (-x) in ‘tentative’,
358    finally recording ‘errno’ in ‘eno’, the "best RCS filename found" in
359    ‘bestfit’, and stat(2) info in ‘status’ (otherwise failing).  */
360 struct maybe
361 {
362   /* Input parameters, constant.  */
363   open_rcsfile_fn *open;
364   bool mustread;
365 
366   /* Input parameter, varying.  */
367   struct cbuf tentative;
368 
369   /* Scratch.  */
370   struct divvy *space;
371 
372   /* Output parameters.  */
373   struct cbuf bestfit;
374   struct stat *status;
375   int eno;
376 };
377 
378 /* The locations of RCS programs, for internal use.  */
379 extern char const prog_diff[];
380 extern char const prog_diff3[];
381 
382 /* Flags to make diff(1) work with RCS.  These
383    should be a single argument (no internal spaces).  */
384 extern char const diff_flags[];
385 
386 /* A string of 77 '=' followed by '\n'.  */
387 extern char const equal_line[];
388 
389 /* Every program defines this.  */
390 struct program
391 {
392   /* The invocation filename, basically a copy of ‘argv[0]’.  */
393   char const *invoke;
394   /* The name of the program, for --help, --version, etc.  */
395   char const *name;
396   /* One-line description, ending with '.' (dot).  */
397   char const *desc;
398   /* Text for --help.  */
399   char const *help;
400   /* What to do when exiting errorfully (see TYAG_* below).  */
401   int const tyag;
402 };
403 
404 /* (Somewhat) fleeting files.  */
405 enum maker { notmade, real, effective };
406 
407 struct sff
408 {
409   char const *filename;
410   /* Unlink this when done.  */
411   enum maker disposition;
412   /* (But only if it is in the right mood.)  */
413 };
414 
415 /* A program controls the behavior of subsystems by setting these.
416    Subsystems also communicate via these settings.  */
417 struct behavior
418 {
419   char const *invdir;
420   /* The directory portion of ‘PROGRAM (invoke)’.
421      -- find_peer_prog  */
422 
423   bool unbuffered;
424   /* Although standard error should be unbuffered by default,
425      don't rely on it.
426      -- unbuffer_standard_error  */
427 
428   bool quiet;
429   /* This is set from command-line option ‘-q’.  When set:
430      - disable all yn -- yesorno
431      - disable warnings -- generic_warn
432      - disable error messages -- diagnose catchsigaction
433      - don't ask about overwriting a writable workfile
434      - on missing RCS file, suppress error and init instead -- pairnames
435      - [ident] suppress no-keywords-found warning
436      - [rcs] suppress yn when outdating all revisions
437      - [rcsclean] suppress progress output  */
438 
439   bool interactive_valid;               /* -- ttystdin */
440   bool interactive;
441   /* Should we act as if stdin is a tty?  Set from ‘-I’.  When set:
442      - enables stdin flushing and newline output -- getcstdin
443      - enables yn (masked by ‘quiet’, above) -- yesorno
444      - enables "enter FOO terminated by ." message -- getsstdin
445      - [co] when workfile writable, include name in error message  */
446 
447   bool inclusive_of_Locker_in_Id_val;
448   /* If set, append locker val when expanding ‘Id’ and locking.  */
449 
450   bool strictly_locking;
451   /* When set:
452      - don't inhibit error when removing self-lock -- removelock
453      - enable error if not self-lock -- addelta
454      - generate "; strict" in RCS file -- putadmin
455      - [ci] ???
456      - [co] conspires w/ kwsub_v to make workfile readonly
457      - [rlog] display "strict"  */
458 
459   bool version_set;
460   int version;
461   /* The "effective RCS version", for backward compatibility,
462      normalized via ‘VERSION’ (i.e., current 0, previous -1, etc).
463      ‘version_set’ true means the effective version was set from the
464      command-line option ‘-V’.  Additional ‘-V’ results in a warning.
465      -- setRCSversion  */
466 
467   bool stick_with_euid;
468   /* Ignore all calls to ‘seteid’ and ‘setrid’.
469      -- nosetid  */
470 
471   int ruid, euid;
472   bool ruid_cached, euid_cached;
473   /* The real and effective user-ids, and their respective
474      "already-cached" state (to implement one-shot).
475      -- ruid euid  */
476 
477   bool already_setuid;
478   /* It's not entirely clear what this bit does.
479      -- set_uid_to  */
480 
481   int kws;
482   /* The keyword substitution (aka "expansion") mode, or -1 (mu).
483      FIXME: Unify with ‘enum kwsub’.
484      -- [co]main [rcs]main [rcsclean]main InitAdmin  */
485 
486   char const *pe;
487   /* Possible endings, a slash-separated list of filename-end
488      fragments to consider for recognizing the name of the RCS file.
489      -- [ci]main [co]main [rcs]main [rcsclean]main [rcsdiff]main
490      -- rcssuffix
491      -- [rcsmerge]main [rlog]main  */
492 
493   struct zone_offset
494   {
495     bool valid;
496     /* When set, use ‘BE (zone_offset.seconds)’ in ‘date2str’.
497        Otherwise, use UTC without timezone indication.
498        -- zone_set  */
499 
500     long seconds;
501     /* Seconds east of UTC, or ‘TM_LOCAL_ZONE’.
502        -- zone_set  */
503   } zone_offset;
504 
505   char *username;
506   /* The login id of the program user.
507      -- getusername  */
508 
509   struct timespec now;
510   /* Cached time from ‘gettime’.
511      -- now  */
512 
513   bool fixed_SIGCHLD;
514   /* True means SIGCHLD handler has been manually set to SIG_DFL.
515      (Only meaningful if ‘BAD_WAIT_IF_SIGCHLD_IGNORED’.)
516      -- runv  */
517 
518   bool Oerrloop;
519   /* True means ‘Oerror’ was called already.
520      -- Oerror  */
521 
522   char *cwd;
523   /* The current working directory.
524      -- getfullRCSname  */
525 
526   off_t mem_limit;
527   /* If a fro is smaller than ‘mem_limit’ kilobytes, try to mmap(2) it
528      (if mmap(2)), or operate on a copy of it in core (if no mmap(2)).
529      Otherwise, use standard i/o routines as the fallback.
530      Set by env var ‘RCS_MEM_LIMIT’.
531      See also ‘MEMORY_UNLIMITED’.
532      -- gnurcs_init  */
533 
534   struct sff *sff;
535   /* (Somewhat) fleeting files.  */
536 
537   /* The rest of the members in ‘struct behavior’ are scratch spaces
538      managed by various subsystems.  */
539 
540   struct isr_scratch *isr;
541   struct ephemstuff *ephemstuff;
542   struct maketimestuff *maketimestuff;
543 };
544 
545 /* The working file is a manifestation of a particular revision.  */
546 struct manifestation
547 {
548   /* What it's called on disk; may be relative,
549      unused if writing to stdout.
550      -- rcsreadopen  */
551   char *filename;
552 
553   /* [co] Use this if writing to stdout.  */
554   FILE *standard_output;
555 
556   /* Previous keywords, to accomodate ‘ci -k’.
557      -- getoldkeys  */
558   struct {
559     bool valid;
560     char *author;
561     char *date;
562     char *name;
563     char *rev;
564     char *state;
565   } prev;
566 };
567 
568 /* The repository file contains a tree of revisions, plus metadata.
569    This is represented by two structures: ‘repo’ is allocated and
570    populated by the parser, while ‘repository’ is library-wide.
571    (It remains to be seen which will swallow the other, if ever.)
572    All lists may be NULL, which means empty.  */
573 struct repo
574 {
575   char const *head;
576   /* Revision number of the tip of the default branch, or NULL.  */
577 
578   char const *branch;
579   /* Default branch number, or NULL.  */
580 
581   size_t access_count;
582   struct link *access;
583   /* List of usernames who may write the RCS file.  */
584 
585   size_t symbols_count;
586   struct link *symbols;
587   /* List of symbolic name definitions (struct symdef).  */
588 
589   size_t locks_count;
590   struct link *locks;
591   /* List of locks (struct rcslock).  */
592 
593   bool strict;
594   /* True if strict locking is to be done.  */
595 
596   struct atat *integrity;
597   /* Checksums and other compacted redundancies.  */
598 
599   struct atat *comment;
600   /* The pre-v5 "comment leader", or NULL.  */
601 
602   int expand;
603   /* The keyword substitution mode (enum kwsub), or -1.  */
604 
605   size_t deltas_count;
606   struct wlink *deltas;
607   /* List of deltas (struct delta).  */
608 
609   struct atat *desc;
610   /* Description of the RCS file.  */
611 
612   off_t neck;
613   /* Parser internal; transitional.
614      (The previous parser design did input and output in one pass, with
615      the (input) file position an implicit state.  The current design
616      does a full scan on input, remembering some key file positions
617      (in this case, the position immediately after the ‘desc’ keyword)
618      and re-synching during output.  Over time we plan to make the
619      output routines not rely on file position.)  */
620 
621   struct lockdef *lockdefs;
622   struct hash *ht;
623   /* Parser internal.  */
624 };
625 
626 struct repository
627 {
628   char const *filename;
629   /* What it's called on disk.
630      -- pairnames  */
631 
632   int fd_lock;
633   /* The file descriptor of the RCS file lockfile.
634      -- rcswriteopen ORCSclose pairnames putadmin  */
635 
636   struct stat stat;
637   /* Stat info, possibly munged.
638      -- [ci]main [rcs]main fro_open (via rcs{read,write}open)  */
639 
640   struct repo *r;
641   /* The result of parsing ‘filename’.
642      -- pairnames  */
643 
644   struct delta *tip;
645   /* The revision on the tip of the default branch.
646      -- addelta buildtree [rcs]main InitAdmin  */
647 
648   struct cbuf log_lead;
649   /* The string to use to start lines expanded for ‘Log’.  FIXME:ZONK.
650      -- [rcs]main InitAdmin  */
651 };
652 
653 /* Various data streams flow in and out of RCS programs.  */
654 struct flow
655 {
656   struct fro *from;
657   /* Input stream for the RCS file.
658      -- rcsreadopen pairnames  */
659 
660   FILE *rewr;
661   /* Output stream for echoing input stream.
662      -- putadmin  */
663 
664   FILE *to;
665   /* Output stream for the RCS file.
666      ``Copy of ‘rewr’, but NULL to suppress echo.''
667      -- [ci]main scanlogtext dorewrite putdesc  */
668 
669   FILE *res;
670   /* Output stream for the result file.  ???
671      -- enterstring  */
672 
673   char const *result;
674   /* The result file name.
675      -- openfcopy swapeditfiles  */
676 
677   bool erroneous;
678   /* True means some (parsing/merging) error was encountered.
679      The program should clean up temporary files and exit.
680      -- buildjoin syserror generic_error generic_fatal  */
681 };
682 
683 /* The top of the structure tree.  */
684 struct top
685 {
686   struct program const *program;
687   struct behavior behavior;
688   struct manifestation manifestation;
689   struct repository repository;
690   struct flow flow;
691 };
692 
693 extern struct top *top;
694 
695 /* In the future we might move ‘top’ into another structure.
696    These abstractions keep the invasiveness to a minimum.  */
697 #define PROGRAM(x)    (top->program-> x)
698 #define BE(quality)   (top->behavior. quality)
699 #define MANI(member)  (top->manifestation. member)
700 #define PREV(which)   (MANI (prev). which)
701 #define REPO(member)  (top->repository. member)
702 #define GROK(member)  (REPO (r)-> member)
703 #define FLOW(member)  (top->flow. member)
704 
705 /* b-anchor */
706 extern char const ks_revno[];
707 extern TINY_DECL (ciklog);
708 extern TINY_DECL (access);
709 extern TINY_DECL (author);
710 extern TINY_DECL (branch);
711 extern TINY_DECL (branches);
712 extern TINY_DECL (comment);
713 extern TINY_DECL (commitid);
714 extern TINY_DECL (date);
715 extern TINY_DECL (desc);
716 extern TINY_DECL (expand);
717 extern TINY_DECL (head);
718 extern TINY_DECL (integrity);
719 extern TINY_DECL (locks);
720 extern TINY_DECL (log);
721 extern TINY_DECL (next);
722 extern TINY_DECL (state);
723 extern TINY_DECL (strict);
724 extern TINY_DECL (symbols);
725 extern TINY_DECL (text);
726 bool looking_at (struct tinysym const *sym, char const *start)
727   ALL_NONNULL;
728 int recognize_kwsub (struct cbuf const *x)
729   ALL_NONNULL;
730 int str2expmode (char const *s)
731   ALL_NONNULL;
732 char const *kwsub_string (enum kwsub i);
733 bool recognize_keyword (char const *string, struct pool_found *found)
734   ALL_NONNULL;
735 
736 /* merger */
737 int merge (bool tostdout, char const *edarg,
738            struct symdef three_manifestations[3])
739   ARG_NONNULL ((3));
740 
741 /* rcsedit */
742 struct editstuff *make_editstuff (void);
743 void unmake_editstuff (struct editstuff *es)
744   ALL_NONNULL;
745 int un_link (char const *s)
746   ALL_NONNULL;
747 void openfcopy (FILE *f);
748 void finishedit (struct editstuff *es, struct delta const * delta,
749                  FILE *outfile, bool done);
750 void snapshotedit (struct editstuff *es, FILE *f)
751   ALL_NONNULL;
752 void copystring (struct editstuff *es, struct atat *atat)
753   ALL_NONNULL;
754 void enterstring (struct editstuff *es, struct atat *atat)
755   ALL_NONNULL;
756 void editstring (struct editstuff *es, struct atat const *script,
757                  struct delta const *delta)
758   ARG_NONNULL ((1, 2));
759 struct fro *rcswriteopen (struct maybe *m)
760   ALL_NONNULL;
761 int chnamemod (FILE **fromp, char const *from, char const *to,
762                int set_mode, mode_t mode, const struct timespec mtime)
763   ALL_NONNULL;
764 int setmtime (char const *file, const struct timespec mtime)
765   ALL_NONNULL;
766 int findlock (bool delete, struct delta **target)
767   ALL_NONNULL;
768 int addsymbol (char const *num, char const *name, bool rebind)
769   ALL_NONNULL;
770 bool checkaccesslist (void);
771 int dorewrite (bool lockflag, int changed);
772 int donerewrite (int changed, const struct timespec mtime);
773 void ORCSclose (void);
774 void ORCSerror (void);
775 exiting
776 void unexpected_EOF (void);
777 void initdiffcmd (struct diffcmd *dc)
778   ALL_NONNULL;
779 int getdiffcmd (struct fro *finfile, bool delimiter,
780                 FILE *foutfile, struct diffcmd *dc)
781   ARG_NONNULL ((1, 4));
782 
783 /* rcsfcmp */
784 int rcsfcmp (struct fro *xfp, struct stat const *xstatp,
785              char const *uname, struct delta const *delta)
786   ALL_NONNULL;
787 
788 /* rcsfnms */
789 char const *basefilename (char const *p)
790   ALL_NONNULL;
791 char const *rcssuffix (char const *name)
792   ALL_NONNULL;
793 struct fro *rcsreadopen (struct maybe *m)
794   ALL_NONNULL;
795 int pairnames (int argc, char **argv, open_rcsfile_fn *rcsopen,
796                bool mustread, bool quiet)
797   ALL_NONNULL;
798 char const *getfullRCSname (void);
799 bool isSLASH (int c);
800 
801 /* rcsgen */
802 char const *buildrevision (struct wlink const *deltas,
803                            struct delta *target,
804                            FILE *outfile, bool expandflag)
805   ARG_NONNULL ((1, 2));
806 struct cbuf cleanlogmsg (char const *m, size_t s)
807   ALL_NONNULL;
808 bool ttystdin (void);
809 int getcstdin (void);
810 bool yesorno (bool default_answer, char const *question, ...)
811   ARG_NONNULL ((2))
812   printf_string (2, 3);
813 void write_desc_maybe (FILE *to);
814 void putdesc (struct cbuf *cb, bool textflag, char *textfile)
815   ARG_NONNULL ((1));
816 struct cbuf getsstdin (char const *option, char const *name, char const *note)
817   ALL_NONNULL;
818 void format_assocs (FILE *out, char const *fmt)
819   ALL_NONNULL;
820 void format_locks (FILE *out, char const *fmt)
821   ALL_NONNULL;
822 void putadmin (void);
823 void puttree (struct delta const *root, FILE *fout)
824   ARG_NONNULL ((2));
825 bool putdtext (struct delta const *delta, char const *srcname,
826                FILE *fout, bool diffmt)
827   ALL_NONNULL;
828 void putstring (FILE *out, struct cbuf s, bool log)
829   ALL_NONNULL;
830 void putdftext (struct delta const *delta, struct fro *finfile,
831                 FILE *foutfile, bool diffmt)
832   ALL_NONNULL;
833 
834 /* rcskeep */
835 bool getoldkeys (struct fro *fp);
836 
837 /* rcsmap */
838 extern enum tokens const ctab[];
839 char const *checkid (char const *id, int delimiter)
840   ALL_NONNULL;
841 char const *checksym (char const *sym, int delimiter)
842   ALL_NONNULL;
843 void checksid (char const *id)
844   ALL_NONNULL;
845 void checkssym (char const *sym)
846   ALL_NONNULL;
847 
848 /* rcsrev */
849 int countnumflds (char const *s);
850 struct cbuf take (size_t count, char const *ref)
851   ALL_NONNULL;
852 int cmpnum (char const *num1, char const *num2);
853 int cmpnumfld (char const *num1, char const *num2, int fld)
854   ALL_NONNULL;
855 int cmpdate (char const *d1, char const *d2)
856   ALL_NONNULL;
857 int compartial (char const *num1, char const *num2, int length)
858   ALL_NONNULL;
859 struct delta *genrevs (char const *revno, char const *date,
860                        char const *author, char const *state,
861                        struct wlink **store)
862   ARG_NONNULL ((1));
863 struct delta *gr_revno (char const *revno, struct wlink **store)
864   ALL_NONNULL;
865 struct delta *delta_from_ref (char const *ref)
866   ALL_NONNULL;
867 bool fully_numeric (struct cbuf *ans, char const *source, struct fro *fp)
868   ARG_NONNULL ((1));
869 char const *namedrev (char const *name, struct delta *delta)
870   ARG_NONNULL ((2));
871 char const *tiprev (void);
872 
873 /* rcstime */
874 void time2date (time_t unixtime, char date[DATESIZE])
875   ALL_NONNULL;
876 void str2date (char const *source, char target[DATESIZE])
877   ALL_NONNULL;
878 time_t date2time (char const source[DATESIZE])
879   ALL_NONNULL;
880 void zone_set (char const *s)
881   ALL_NONNULL;
882 char const *date2str (char const date[DATESIZE],
883                       char datebuf[FULLDATESIZE])
884   ALL_NONNULL;
885 
886 /* rcsutil */
887 exiting
888 void thank_you_and_goodnight (int const how);
889 /* These are for ‘thank_you_and_goodnight’.  */
890 #define TYAG_ORCSERROR     (1 << 3)
891 #define TYAG_DIRTMPUNLINK  (1 << 2)
892 #define TYAG_TEMPUNLINK    (1 << 1)
893 #define TYAG_DIFF          (1 << 0)
894 #define TYAG_IMMEDIATE           0
895 
896 void gnurcs_init (struct program const *program)
897   ALL_NONNULL;
898 void gnurcs_goodbye (void);
899 void bad_option (char const *option)
900   ALL_NONNULL;
901 void redefined (int c);
902 void chk_set_rev (const char **rev, char *arg)
903   ALL_NONNULL;
904 struct cbuf minus_p (char const *xrev, char const *rev)
905   ALL_NONNULL;
906 void parse_revpairs (char option, char *arg, void *data,
907                      void (*put) (char const *b, char const *e,
908                                   bool sawsep, void *data))
909   ALL_NONNULL;
910 void set_empty_log_message (struct cbuf *cb)
911   ALL_NONNULL;
912 void ffree (void);
913 char *str_save (char const *s)
914   ALL_NONNULL;
915 char *cgetenv (char const *name)
916   ALL_NONNULL;
917 void awrite (char const *buf, size_t chars, FILE *f)
918   ALL_NONNULL;
919 int runv (int infd, char const *outname, char const **args)
920   ARG_NONNULL ((3));
921 int run (int infd, char const *outname, ...);
922 void setRCSversion (char const *str)
923   ALL_NONNULL;
924 int getRCSINIT (int argc, char **argv, char ***newargv)
925   ALL_NONNULL;
926 struct timespec unspecified_timespec (void);
927 struct timespec file_mtime (bool enable, struct stat const *st)
928   ALL_NONNULL;
929 
930 /* Indexes into ‘BE (sff)’.  */
931 #define SFFI_LOCKDIR  0
932 #define SFFI_NEWDIR   BAD_CREAT0
933 
934 /* Idioms.  */
935 
936 #define TIME_UNSPECIFIED       ((time_t) -1)
937 #define TIME_UNSPECIFIED_P(x)  ((x) == TIME_UNSPECIFIED)
938 
939 /* This is for ‘ns’ (2nd) arg to ‘make_timespec’.  */
940 #define ZERO_NANOSECONDS  0
941 
942 #define MEMORY_UNLIMITED  -1
943 
944 #define BOG_DIFF   (TYAG_TEMPUNLINK | TYAG_DIFF)
945 #define BOG_ZONK   (TYAG_DIRTMPUNLINK | TYAG_TEMPUNLINK)
946 #define BOG_FULL   (TYAG_ORCSERROR | BOG_ZONK)
947 
948 #define BOW_OUT()  thank_you_and_goodnight (PROGRAM (tyag))
949 
950 /* Murphy was an optimist...  */
951 #define PROB(x)  (0 > (x))
952 
953 #define clear_buf(b)  (((b)->string = NULL, (b)->size = 0))
954 
955 #define STR_DIFF(a,b)  (strcmp ((a), (b)))
956 #define STR_SAME(a,b)  (! STR_DIFF ((a), (b)))
957 
958 /* Get a character from ‘fin’, perhaps copying to a ‘frew’.  */
959 #define TEECHAR()  do                           \
960     {                                           \
961       GETCHAR (c, fin);                         \
962       if (frew)                                 \
963         afputc (c, frew);                       \
964     }                                           \
965   while (0)
966 
967 #define TAKE(count,rev)  (take (count, rev).string)
968 
969 #define BRANCHNO(rev)    TAKE (0, rev)
970 
971 #define fully_numeric_no_k(cb,source)  fully_numeric (cb, source, NULL)
972 
973 #define TINYS(x)  ((char const *)(x)->bytes)
974 
975 #define TINYKS(x)  TINYS (&TINY (x))
976 
977 #define GENERIC_COMPARE(fn,...)  (cmp ## fn (__VA_ARGS__))
978 #define GENERIC_LT(fn,...)       (0 >  GENERIC_COMPARE (fn, __VA_ARGS__))
979 #define GENERIC_EQ(fn,...)       (0 == GENERIC_COMPARE (fn, __VA_ARGS__))
980 #define GENERIC_GT(fn,...)       (0 <  GENERIC_COMPARE (fn, __VA_ARGS__))
981 
982 #define NUM_LT(a,b)  GENERIC_LT (num, a, b)
983 #define NUM_EQ(a,b)  GENERIC_EQ (num, a, b)
984 #define NUM_GT(a,b)  GENERIC_GT (num, a, b)
985 
986 #define DATE_LT(a,b)  GENERIC_LT (date, a, b)
987 #define DATE_EQ(a,b)  GENERIC_EQ (date, a, b)
988 #define DATE_GT(a,b)  GENERIC_GT (date, a, b)
989 
990 #define NUMF_LT(nf,a,b)  GENERIC_LT (numfld, a, b, nf)
991 #define NUMF_EQ(nf,a,b)  GENERIC_EQ (numfld, a, b, nf)
992 
993 #define MEM_SAME(n,a,b)  (0 == memcmp ((a), (b), (n)))
994 #define MEM_DIFF(n,a,b)  (0 != memcmp ((a), (b), (n)))
995 
996 #define ODDP(n)   ((n) & 1)
997 #define EVENP(n)  (! ODDP (n))
998 
999 /* base.h ends here */
1000