home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / netsrcs / latex_2.idx < prev    next >
Internet Message Format  |  1986-05-31  |  57KB

  1. From simpson@trwrb.UUCP (Scott Simpson) Fri May 30 20:19:30 1986
  2. Path: seismo!lll-crg!styx!nike!cad!ucbvax!sdcsvax!sdcrdcf!trwrb!simpson
  3. From: simpson@trwrb.UUCP (Scott Simpson)
  4. Newsgroups: net.sources
  5. Subject: LaTeX Index Processor (Part 2)
  6. Message-ID: <1110@trwrb.UUCP>
  7. Date: 31 May 86 00:19:30 GMT
  8. Organization: TRW EDS, Redondo Beach, CA
  9. Lines: 2864
  10. Keywords: LaTeX, Index Processor
  11.  
  12. #! /bin/sh
  13. # To extract, remove mail header lines and type "sh filename"
  14. if [ ! -d libglob ]
  15. then
  16.     mkdir libglob
  17.     echo mkdir libglob
  18. fi
  19. echo x - libglob/Makefile
  20. sed -e 's/^X//' > libglob/Makefile << '!FaR!OuT!'
  21. X# @(#)Makefile    1.1 (TRW) 1/14/86
  22. X
  23. XCFLAGS = -O
  24. XOBJECTS = glob.o
  25. XDESTDIR = /
  26. XINCLUDE = /usr/include/local
  27. X
  28. X.c.o:
  29. X    ${CC} ${CFLAGS} -c $*.c
  30. X    -ld -x -r $*.o
  31. X    mv a.out $*.o
  32. X
  33. Xall: libglob.a
  34. X
  35. Xlibglob.a: ${OBJECTS}
  36. X    ar cr libglob.a ${OBJECTS}
  37. X    ranlib libglob.a
  38. X    chmod 644 libglob.a
  39. X
  40. Xinstall: all
  41. X    mv libglob.a ${DESTDIR}/usr/local/lib
  42. X    ranlib ${DESTDIR}/usr/local/lib/libglob.a
  43. X    install -c glob.h ${INCLUDE}/glob.h
  44. X
  45. Xclean:
  46. X    rm -f *.o
  47. !FaR!OuT!
  48. if [ ! -d libglob ]
  49. then
  50.     mkdir libglob
  51.     echo mkdir libglob
  52. fi
  53. echo x - libglob/glob.3
  54. sed -e 's/^X//' > libglob/glob.3 << '!FaR!OuT!'
  55. X.\" %W% (TRW) %G%
  56. X.TH GLOB 3 TRW
  57. X.UC
  58. X.SH NAME
  59. Xglob \- shell style pattern matching
  60. X.SH SYNOPSIS
  61. X.nf
  62. X.B #include <local/glob.h>
  63. X
  64. X.B int glob_compile(pattern, buffer)
  65. X.B char *pattern;
  66. X.B char *buffer;
  67. X
  68. X.B int glob_execute(buffer, s)
  69. X.B char *buffer;
  70. X.B char *s;
  71. X
  72. X.B int glob_match (pattern, s)
  73. X.B char *pattern;
  74. X.B char *s;
  75. X.fi
  76. X
  77. X.B cc 
  78. X[ flags ] files
  79. X.B -lglob
  80. X[ libraries ]
  81. X.fi
  82. X.SH DESCRIPTION
  83. X.I Glob
  84. Xis a pattern matching facility similar to that of
  85. X.IR sh (1)
  86. Xand
  87. X.IR csh (1).
  88. X.PP
  89. XA pattern specifies a set of strings of characters.
  90. XA member of this set of strings is said to be matched by the pattern.
  91. X.TP
  92. X(1)
  93. XAny character except a special character matches itself.
  94. XThe special characters are [ * and ?.
  95. X.TP
  96. X(2)
  97. XA ? matches any character.
  98. X.TP
  99. X(3)
  100. XA nonempty string
  101. X.I s
  102. Xbracketed
  103. X.RI [ s ]
  104. Xmatches any character in
  105. X.IR s .
  106. XIn
  107. X.I s
  108. X] may only appear as the first letter.
  109. XA substring
  110. X.IR a \- b ,
  111. Xwith
  112. X.I a
  113. Xand
  114. X.I b
  115. Xin ascending ASCII order,
  116. Xstands for the inclusive range of ASCII characters.
  117. X.TP
  118. X(4)
  119. XA * matches 0 or more characters.
  120. X.PP
  121. X.I Glob_compile
  122. Xcompiles a
  123. X.I pattern
  124. Xinto an internal form suitable for matching,
  125. Xplacing the result in the character array
  126. X.IR buffer .
  127. X.I Buffer
  128. Xmust be a character array of size
  129. X.BR GLOB_MAX_PATTERN .
  130. X.I Glob_compile
  131. Xreturns 0 if the
  132. X.I pattern
  133. Xwas compiled successfully;
  134. Xotherwise a negative error code is returned.
  135. X.PP
  136. X.I Glob_execute
  137. Xchecks the argument string
  138. X.I s
  139. Xagainst the compiled
  140. X.IR pattern .
  141. X.I Glob_execute
  142. Xreturns 1 if the string
  143. X.I s
  144. Xmatches the compiled pattern in
  145. X.IR buffer ,
  146. X0 if the string
  147. X.I s
  148. Xfailed to match the compiled pattern in
  149. X.IR buffer ,
  150. Xand a negative error code if the compiled pattern was invalid.
  151. X.PP
  152. XThe strings passed to both
  153. X.I glob_compile
  154. Xand
  155. X.I glob_execute
  156. Xmay have trailing or embedded newline characters;
  157. Xthey are terminated by nulls.
  158. X.PP
  159. X.I Glob_match
  160. Xcompiles
  161. X.I pattern
  162. Xand matches it against the argument string
  163. X.IR s .
  164. XIt returns 1 if the string
  165. X.I s
  166. Xmatches the pattern;
  167. X0 if the string
  168. X.I s
  169. Xfails to match the pattern
  170. Xand a negative error code if the pattern was invalid.
  171. X.SH AUTHOR
  172. XMichael Gorlick, TRW
  173. X.SH SEE ALSO
  174. Xregex(3)
  175. X.SH DIAGNOSTICS
  176. XThe following diagnostic codes are provided:
  177. X.TP
  178. XGLOB_OK
  179. Xreturned by
  180. X.I glob_compile
  181. Xindicating the pattern compiled successfully;
  182. X.TP
  183. XGLOB_PATTERN_TOO_BIG
  184. Xreturned by
  185. X.I glob_compile
  186. Xor
  187. X.I glob_match
  188. Xindicating the compiled pattern overflowed the buffer;
  189. X.TP
  190. XGLOB_PATTERN_EMPTY
  191. Xreturned by
  192. X.I glob_compile
  193. Xor
  194. X.I glob_match
  195. Xindicating the pattern is the empty string;
  196. X.TP
  197. XGLOB_BRACKET_MISSING
  198. Xreturned by
  199. X.I glob_compile
  200. Xor
  201. X.I glob_match
  202. Xindicating that a set expression
  203. X.RI [ s ]
  204. Xis missing the terminating bracket ];
  205. X.TP
  206. XGLOB_RANGE_INVERTED
  207. Xreturned by
  208. X.I glob_compile
  209. Xor
  210. X.I glob_match
  211. Xindicating a range expression in a set
  212. Xis inverted, for example [z-a];
  213. X.TP
  214. XGLOB_SET_TOO_BIG
  215. Xreturned by
  216. X.I glob_compile
  217. Xor
  218. X.I glob_match
  219. Xindicating a compiled set requires more than 127 bytes
  220. X(a single character consumes 2 bytes and a range consumes 3 bytes);
  221. X.TP
  222. XGLOB_EXECUTION_ERROR
  223. Xreturned by
  224. X.I glob_execute
  225. Xor
  226. X.I glob_match
  227. Xindicating an internal error.
  228. !FaR!OuT!
  229. if [ ! -d libglob ]
  230. then
  231.     mkdir libglob
  232.     echo mkdir libglob
  233. fi
  234. echo x - libglob/glob.c
  235. sed -e 's/^X//' > libglob/glob.c << '!FaR!OuT!'
  236. Xstatic char *trwsccs= "@(#)glob.c    1.1 (TRW) 1/14/86";
  237. X#include "glob.h"
  238. X
  239. X#define SLOP 5
  240. X#define MAX_SET 0177
  241. X
  242. X/* control codes for regular expression evaluation */
  243. X#define PATTERN_ANY '?'
  244. X#define PATTERN_CHARACTER 'X'
  245. X#define PATTERN_END '$'
  246. X#define PATTERN_SET '['
  247. X#define PATTERN_SET_MEMBER 'M'
  248. X#define PATTERN_SET_RANGE '-'
  249. X#define PATTERN_STAR '*'
  250. X
  251. X/*
  252. X * Examples (=> denotes `compiles into')
  253. X *
  254. X *    a    =>    Xa
  255. X *    ?    =>    ?
  256. X *    [x0-9]    =>    [^EMx-09    (^E is control-E)
  257. X *    *    =>    *
  258. X *    END    =>    $
  259. X *
  260. X *    a?[x0-9]* => Xa?[^EMx-09*$
  261. X */
  262. X
  263. Xglob_compile (pattern, buffer)
  264. Xchar *pattern;
  265. Xchar *buffer;    /* compiled pattern */
  266. X{
  267. X    char *x;    /* pointer into compiled pattern */
  268. X    int c;
  269. X    int result;
  270. X
  271. X    if (pattern == 0 || pattern[0] == 0)
  272. X        return(GLOB_PATTERN_EMPTY);
  273. X
  274. X    x = buffer;
  275. X    while (x < &buffer[GLOB_MAX_PATTERN - SLOP]) {
  276. X        c = *pattern++;
  277. X        if (c == 0) {
  278. X            *x++ = PATTERN_END;
  279. X            return(GLOB_OK);
  280. X        }
  281. X
  282. X        switch (c) {
  283. X        case '?':
  284. X            *x++ = PATTERN_ANY;
  285. X            continue;
  286. X
  287. X        case '[':
  288. X            if ((result = compile_set(pattern, x, &buffer[GLOB_MAX_PATTERN - SLOP])) < 0)
  289. X                return(result);
  290. X            pattern += result + 1;
  291. X            x += x[1] + 2;
  292. X            continue;
  293. X
  294. X        case '*':
  295. X            *x++ = PATTERN_STAR;
  296. X            continue;
  297. X
  298. X        default:
  299. X            *x++ = PATTERN_CHARACTER;
  300. X            *x++ = c;
  301. X            continue;
  302. X        }
  303. X    }
  304. X    return(GLOB_PATTERN_TOO_BIG);
  305. X}
  306. X
  307. Xint glob_execute (pattern, s)
  308. Xchar *pattern;    /* compiled pattern */
  309. Xchar *s;    /* string to be matched against */
  310. X{
  311. X    char *current;
  312. X    int result;
  313. X
  314. X    for (;;)
  315. X        switch (*pattern++) {
  316. X        case PATTERN_ANY:
  317. X            if (*s++)
  318. X                continue;
  319. X            return(0);
  320. X
  321. X        case PATTERN_CHARACTER:
  322. X            if (*pattern++ == *s++)
  323. X                continue;
  324. X            return(0);
  325. X
  326. X        case PATTERN_END:
  327. X            return(*s == 0);
  328. X
  329. X        case PATTERN_SET:
  330. X            if ((result = in_set(pattern, *s++)) == 1) {
  331. X                pattern += *pattern + 1;
  332. X                continue;
  333. X            }
  334. X            return(result);
  335. X
  336. X        case PATTERN_STAR:
  337. X            current = s;
  338. X            while (*s++)
  339. X                continue;
  340. X            do {
  341. X                s--;
  342. X                if (result = glob_execute(pattern, s))
  343. X                    return(result);
  344. X            } while (s > current);
  345. X            return(0);
  346. X
  347. X        default:
  348. X            return(GLOB_EXECUTION_ERROR);
  349. X        }
  350. X}
  351. X
  352. Xint glob_match (pattern, s)
  353. Xchar *pattern;
  354. Xchar *s;
  355. X{
  356. X    int result;
  357. X    char buffer[GLOB_MAX_PATTERN];
  358. X
  359. X    if ((result = glob_compile(pattern, buffer)) < 0)
  360. X        return(result);
  361. X    else
  362. X        return(glob_execute(buffer, s));
  363. X}
  364. X
  365. X/* returns 1 if character c is member of set and 0 otherwise */
  366. Xstatic int in_set (set, c)
  367. Xchar *set;    /* compiled set pattern */
  368. Xchar c;
  369. X{
  370. X    int n;
  371. X
  372. X    if (c == 0)
  373. X        return(0);
  374. X    n = *set++;
  375. X    while (n > 0)
  376. X        switch (*set++) {
  377. X        case PATTERN_SET_MEMBER:
  378. X            if (*set++ == c)
  379. X                return(1);
  380. X            n -= 2;
  381. X            continue;
  382. X
  383. X        case PATTERN_SET_RANGE:
  384. X            if (*set++ <= c && c <= *set++)
  385. X                return(1);
  386. X            n -= 3;
  387. X            continue;
  388. X
  389. X        default:
  390. X            return(GLOB_EXECUTION_ERROR);
  391. X        }
  392. X    return(0);
  393. X}
  394. X
  395. X#define IS_RANGE(s) (s[1] && s[2] && s[1] == '-' && s[2] != ']')
  396. X
  397. X/* compiles a set returning the number of pattern characters consumed */
  398. Xstatic int compile_set (pattern, x, limit)
  399. Xchar *pattern;
  400. Xchar *x;
  401. Xchar *limit;
  402. X{
  403. X    char *slot;    /* size of set goes here */
  404. X    int size;    /* number of bytes in compiled set */
  405. X    char *start = pattern;
  406. X
  407. X    if (*pattern == 0)
  408. X        return(GLOB_BRACKET_MISSING);
  409. X
  410. X    *x++ = PATTERN_SET;
  411. X    slot = x++;
  412. X    size = 0;
  413. X
  414. X    if (IS_RANGE(pattern)) {
  415. X        if (pattern[0] > pattern[2])    /* pattern[1] == '-' */
  416. X            return(GLOB_RANGE_INVERTED);
  417. X        *x++ = PATTERN_SET_RANGE;
  418. X        *x++ = pattern[0];
  419. X        *x++ = pattern[2];
  420. X        pattern += 3;
  421. X        size += 3;
  422. X    } else {
  423. X        *x++ = PATTERN_SET_MEMBER;
  424. X        *x++ = *pattern++;
  425. X        size += 2;
  426. X    }
  427. X
  428. X    while (*pattern != ']' && x < limit) {
  429. X        if (*pattern == 0)
  430. X            return(GLOB_BRACKET_MISSING);
  431. X        if (IS_RANGE(pattern)) {
  432. X            if (pattern[0] > pattern[2])    /* pattern[1] == '-' */
  433. X                return(GLOB_RANGE_INVERTED);
  434. X            *x++ = PATTERN_SET_RANGE;
  435. X            *x++ = pattern[0];
  436. X            *x++ = pattern[2];
  437. X            pattern += 3;
  438. X            size += 3;
  439. X        } else {
  440. X            *x++ = PATTERN_SET_MEMBER;
  441. X            *x++ = *pattern++;
  442. X            size += 2;
  443. X        }
  444. X    }
  445. X    if (size > MAX_SET)
  446. X        return(GLOB_SET_TOO_BIG);
  447. X    *slot = size;
  448. X    return(pattern - start);
  449. X}
  450. !FaR!OuT!
  451. if [ ! -d libglob ]
  452. then
  453.     mkdir libglob
  454.     echo mkdir libglob
  455. fi
  456. echo x - libglob/glob.h
  457. sed -e 's/^X//' > libglob/glob.h << '!FaR!OuT!'
  458. X/* @(#)glob.h    1.1 (TRW) 1/14/86 */
  459. X#define GLOB_MAX_PATTERN    1024
  460. X#define GLOB_OK            0
  461. X#define GLOB_PATTERN_TOO_BIG    -1
  462. X#define GLOB_PATTERN_EMPTY    -2
  463. X#define GLOB_BRACKET_MISSING    -3
  464. X#define GLOB_RANGE_INVERTED    -4
  465. X#define GLOB_SET_TOO_BIG    -5
  466. X#define GLOB_EXECUTION_ERROR    -6
  467. !FaR!OuT!
  468. if [ ! -d libprofile ]
  469. then
  470.     mkdir libprofile
  471.     echo mkdir libprofile
  472. fi
  473. echo x - libprofile/Makefile
  474. sed -e 's/^X//' > libprofile/Makefile << '!FaR!OuT!'
  475. X# @(#)Makefile    1.1 (TRW) 1/14/86
  476. XCFLAGS = -O
  477. XOBJECTS = boolean.o free.o has.o read.o space.o write.o
  478. XDEST = /usr/local
  479. X
  480. X.c.o:
  481. X    ${CC} ${CFLAGS} -c $*.c
  482. X    -ld -r -x $*.o
  483. X    mv a.out $*.o
  484. X
  485. Xall: libprofile.a
  486. X
  487. Xlibprofile.a: ${OBJECTS}
  488. X    ar cr libprofile.a ${OBJECTS}
  489. X    ranlib libprofile.a
  490. X    chmod 644 libprofile.a
  491. X
  492. Xinstall: all
  493. X    mv libprofile.a ${DEST}/lib
  494. X    ranlib ${DEST}/lib/libprofile.a
  495. X    install -c profile.h /usr/include/local
  496. X
  497. Xclean:
  498. X    rm -f *.o
  499. !FaR!OuT!
  500. if [ ! -d libprofile ]
  501. then
  502.     mkdir libprofile
  503.     echo mkdir libprofile
  504. fi
  505. echo x - libprofile/boolean.c
  506. sed -e 's/^X//' > libprofile/boolean.c << '!FaR!OuT!'
  507. Xstatic char *trwsccs = "@(#)boolean.c    1.1 (TRW) 1/14/86";
  508. X#include <ctype.h>
  509. X#include "profile.h"
  510. X
  511. Xstatic char *Yes[] = {
  512. X    "yes",
  513. X    "on",
  514. X    "true",
  515. X    "enable",
  516. X    "available",
  517. X    "present",
  518. X    0
  519. X};
  520. X
  521. Xstatic char *No[] = {
  522. X    "no",
  523. X    "off",
  524. X    "false",
  525. X    "disable",
  526. X    "unavailable",
  527. X    "absent",
  528. X    0
  529. X};
  530. X
  531. Xint profile_boolean (v)
  532. XPROFILE_VALUE *v;
  533. X{
  534. X    char x[16];
  535. X    int i;
  536. X
  537. X    if (v == 0)
  538. X        return(0);
  539. X
  540. X    switch (v->class) {
  541. X    case PROFILE_OTHER:
  542. X    case PROFILE_STRING:
  543. X        strncpy(x, v->value.s, sizeof(x)-1);
  544. X        x[sizeof(x)-1] = 0;
  545. X        downshift(x);
  546. X        for (i = 0; Yes[i]; i++)
  547. X            if (strcmp(x, Yes[i]) == 0)
  548. X                return(1);
  549. X            else if (strcmp(x, No[i]) == 0)
  550. X                return(0);
  551. X        return(-1);    /* unknown string */
  552. X
  553. X    case PROFILE_HEX:
  554. X    case PROFILE_INTEGER:
  555. X    case PROFILE_OCTAL:
  556. X        return(v->value.i != 0);
  557. X
  558. X    case PROFILE_CHARACTER:
  559. X        return(v->value.c != 0);
  560. X
  561. X    case PROFILE_FLOAT:
  562. X        return(v->value.f != 0.0);
  563. X
  564. X    default:
  565. X        return(-1);    /* unknown class */
  566. X    }
  567. X}
  568. X
  569. X/* downshift a string in place */
  570. Xstatic downshift (s)
  571. Xchar *s;
  572. X{
  573. X    for (; *s; s++)
  574. X        if (isupper(*s))
  575. X            *s = tolower(*s);
  576. X}
  577. !FaR!OuT!
  578. if [ ! -d libprofile ]
  579. then
  580.     mkdir libprofile
  581.     echo mkdir libprofile
  582. fi
  583. echo x - libprofile/free.c
  584. sed -e 's/^X//' > libprofile/free.c << '!FaR!OuT!'
  585. Xstatic char *trwsccs = "@(#)free.c    1.1 (TRW) 1/14/86";
  586. X#include "profile.h"
  587. X
  588. Xprofile_free_profile (s)
  589. XPROFILE_STANZA *s;
  590. X{
  591. X    PROFILE_STANZA *x;
  592. X
  593. X    for (x = s; x != (PROFILE_STANZA *)0 && x != s; x = x->next)
  594. X        profile_free_stanza(x);
  595. X}
  596. X
  597. Xprofile_free_stanza (s)
  598. XPROFILE_STANZA *s;
  599. X{
  600. X    free_markers(s->marker);
  601. X    free_bindings(s->binding);
  602. X    free(s);
  603. X}
  604. X
  605. Xstatic free_markers (m)
  606. XPROFILE_MARKER *m;
  607. X{
  608. X    PROFILE_MARKER *x;
  609. X
  610. X    for (; m; m = x) {
  611. X        x = m->next;
  612. X        free(m);
  613. X    }
  614. X}
  615. X
  616. Xstatic free_bindings (b)
  617. XPROFILE_BINDING *b;
  618. X{
  619. X    PROFILE_BINDING *x;
  620. X
  621. X    for (; b; b = x) {
  622. X        x = b->next;
  623. X        free_values(b->value);
  624. X        free(b);
  625. X    }
  626. X}
  627. X
  628. Xstatic free_values (v)
  629. XPROFILE_VALUE *v;
  630. X{
  631. X    PROFILE_VALUE *x;
  632. X
  633. X    for (; v; v = x) {
  634. X        x = v->next;
  635. X        free(v);
  636. X    }
  637. X}
  638. !FaR!OuT!
  639. if [ ! -d libprofile ]
  640. then
  641.     mkdir libprofile
  642.     echo mkdir libprofile
  643. fi
  644. echo x - libprofile/has.c
  645. sed -e 's/^X//' > libprofile/has.c << '!FaR!OuT!'
  646. Xstatic char *trwsccs = "@(#)has.c    1.1 (TRW) 1/14/86";
  647. X#include <stdio.h>
  648. X#include "profile.h"
  649. X
  650. XPROFILE_MARKER *profile_has_marker (s, m)
  651. XPROFILE_STANZA *s;
  652. Xchar *m;
  653. X{
  654. X    PROFILE_MARKER *x;
  655. X    int result;
  656. X
  657. X    for (x = s->marker; x; x = x->next)
  658. X        if(glob_match(x->text, m) > 0)
  659. X            return(x);
  660. X    return((PROFILE_MARKER *)0);
  661. X}
  662. X
  663. X/*
  664. X * read down a linked list of stanzas looking
  665. X * for a stanza that has the requested markers
  666. X */
  667. XPROFILE_STANZA *profile_has_stanza(s, marker)
  668. XPROFILE_STANZA *s;
  669. Xchar *marker[];        /* terminated by a null pointer */
  670. X{
  671. X    int i;
  672. X    PROFILE_STANZA *x;
  673. X
  674. X    if (s == NULL)
  675. X        return(s);
  676. X    x = s;
  677. X    do {
  678. X        for (i = 0; marker[i] != NULL; i++)
  679. X            if (profile_has_marker(x, marker[i]) == NULL)
  680. X                break;
  681. X        if (marker[i] == NULL)
  682. X            return(x);
  683. X        x = x->next;
  684. X    } while (x != s && x != NULL);
  685. X
  686. X    return((PROFILE_STANZA *)NULL);
  687. X}
  688. X
  689. XPROFILE_BINDING *profile_has_binding (s, b)
  690. XPROFILE_STANZA *s;
  691. Xchar *b;
  692. X{
  693. X    PROFILE_BINDING *x;
  694. X
  695. X    for (x = s->binding; x; x = x->next)
  696. X        if (glob_match(x->name, b) > 0)
  697. X            return(x);
  698. X    return((PROFILE_BINDING *)0);
  699. X}
  700. !FaR!OuT!
  701. if [ ! -d libprofile ]
  702. then
  703.     mkdir libprofile
  704.     echo mkdir libprofile
  705. fi
  706. echo x - libprofile/profile.3
  707. sed -e 's/^X//' > libprofile/profile.3 << '!FaR!OuT!'
  708. X.\" %W% (TRW) %G%
  709. X.TH PROFILE 3 TRW
  710. X.UC 4
  711. X.SH NAME
  712. Xprofile \- read/write configuration files
  713. X.SH SYNOPSIS
  714. X.nf
  715. X.B #include <stdio.h>
  716. X.B #include <local/profile.h>
  717. X
  718. X.B PROFILE_STANZA *profile_read_stanza(f)
  719. X.B FILE *f;
  720. X
  721. X.B PROFILE_STANZA *profile_read_profile(f)
  722. X.B FILE *f;
  723. X
  724. X.B profile_write_stanza(f, s)
  725. X.B FILE *f;
  726. X.B PROFILE_STANZA *s;
  727. X
  728. X.B profile_write_profile(f, s)
  729. X.B FILE *f;
  730. X.B PROFILE_STANZA *s;
  731. X
  732. X.B profile_free_stanza(s)
  733. X.B PROFILE_STANZA *s;
  734. X
  735. X.B PROFILE_MARKER *profile_has_marker(s, m)
  736. X.B PROFILE_STANZA *s;
  737. X.B char *m;
  738. X
  739. X.B PROFILE_STANZA *profile_has_stanza(s, marker)
  740. X.B PROFILE_STANZA *s;
  741. X.B char *marker[];
  742. X
  743. X.B PROFILE_BINDING *profile_has_binding(s, b)
  744. X.B PROFILE_STANZA *s;
  745. X.B char *b;
  746. X
  747. X.B PROFILE_STANZA *profile_stanza_space()
  748. X
  749. X.B PROFILE_MARKER *profile_marker_space(n)
  750. X.B int n;
  751. X
  752. X.B PROFILE_BINDING *profile_binding_space(n)
  753. X.B int n;
  754. X
  755. X.B PROFILE_VALUE *profile_value_space(n)
  756. X.B int n;
  757. X.fi
  758. X.SH DESCRIPTION
  759. X.I Profile_read_stanza
  760. Xreads a single stanza from a configuration file returning
  761. Xa pointer to the stanza if successful and NULL on error or end of file.
  762. XA stanza is defined as:
  763. X.nf
  764. X.ta 1i +\w'typedef 'u
  765. X
  766. X    typedef struct PROFILE_STANZA {
  767. X        PROFILE_MARKER *marker;
  768. X        PROFILE_BINDING *binding;
  769. X        struct PROFILE_STANZA *previous;
  770. X        struct PROFILE_STANZA *next;
  771. X    } PROFILE_STANZA;
  772. X.fi
  773. X.PP
  774. X.I Marker
  775. Xand
  776. X.I binding
  777. Xpoint to linked lists of markers and bindings respectively.
  778. XIf
  779. X.I marker
  780. Xis
  781. X.B NULL
  782. Xthe stanza has no markers.
  783. XIf
  784. X.I binding
  785. Xis
  786. X.B NULL
  787. Xthe stanza has no bindings.
  788. X.I Previous
  789. Xand
  790. X.I next
  791. Xare ignored and may be used to doubly link successive stanzas together.
  792. X.DT
  793. X.PP
  794. XA marker is defined as:
  795. X.nf
  796. X.ta 1i +\w'typedef 'u
  797. X
  798. X    typedef struct PROFILE_MARKER {
  799. X        char *text;
  800. X        struct PROFILE_MARKER *previous;
  801. X        struct PROFILE_MARKER *next;
  802. X    } PROFILE_MARKER;
  803. X.fi
  804. X.DT
  805. X.PP
  806. X.I Text
  807. Xis a string containing the literal text of the marker
  808. Xand is always nonempty.
  809. X.IR Previous " (" next )
  810. Xis a pointer to the previous (next) marker in the sequence.
  811. XIn the first (last) marker
  812. X.IR previous " (" next )
  813. Xis
  814. X.BR NULL .
  815. X.PP
  816. XA binding is defined as:
  817. X.nf
  818. X.ta 1i +\w'typedef 'u
  819. X
  820. X    typedef struct PROFILE_BINDING {
  821. X        char *name;
  822. X        PROFILE_VALUE *value;
  823. X        struct PROFILE_BINDING *previous;
  824. X        struct PROFILE_BINDING *next;
  825. X    } PROFILE_BINDING;
  826. X.fi
  827. X.DT
  828. X.PP
  829. X.I Name
  830. Xis the literal text of the name of the binding and is always nonempty.
  831. X.I Value
  832. Xis a pointer to the list of values associated with the name.
  833. XIf
  834. X.I value
  835. Xis
  836. X.B NULL
  837. Xthen the binding consists solely of a name with no associated value.
  838. X.IR Previous " (" next )
  839. Xpoints to the previous (next) binding in the sequence.
  840. XIn the first (last) binding
  841. X.IR previous " (" next )
  842. Xis
  843. X.BR NULL .
  844. X.PP
  845. XA value is defined as:
  846. X.nf
  847. X.ta 1i +\w'typedef 'u +\w'union { 'u
  848. X
  849. X    typedef struct PROFILE_VALUE {
  850. X        char class;
  851. X        union {
  852. X            long int i;
  853. X            double f;
  854. X            char c;
  855. X            char *s;
  856. X        } value;
  857. X        struct PROFILE_VALUE *previous;
  858. X        struct PROFILE_VALUE *next;
  859. X    } PROFILE_VALUE;
  860. X.fi
  861. X.DT
  862. X.PP
  863. X.I Class
  864. Xis always one of:
  865. X.TP
  866. XPROFILE_CHARACTER
  867. Xthe value is a character constant contained in
  868. X.IR c .
  869. X.TP
  870. XPROFILE_HEX
  871. Xthe value is a hex constant contained in
  872. X.IR i .
  873. X.TP
  874. XPROFILE_INTEGER
  875. Xthe value is an integer constant contained in
  876. X.IR i .
  877. X.TP
  878. XPROFILE_FLOAT
  879. Xthe value is a real constant contained in
  880. X.IR f .
  881. X.TP
  882. XPROFILE_OCTAL
  883. Xthe value is an octal constant contained in
  884. X.IR i .
  885. X.TP
  886. XPROFILE_STRING
  887. Xthe value is a string constant contained in
  888. X.IR s .
  889. X.TP
  890. XPROFILE_OTHER
  891. Xthe value is not recognizably
  892. Xcharacter,
  893. Xhex,
  894. Xinteger,
  895. Xfloat,
  896. Xoctal
  897. Xor string.
  898. XThe literal text is contained in
  899. X.IR s .
  900. X.PP
  901. X.IR Previous " (" next )
  902. Xpoints to the previous (next) value in the sequence.
  903. XIn the first (last) value
  904. X.IR previous " (" next )
  905. Xis
  906. X.BR NULL .
  907. X.PP
  908. X.I Profile_read_profile
  909. Xreads an entire configuration file and builds a bi-directional, 
  910. Xcircularly linked list of stanzas using the 
  911. X.I previous
  912. Xand 
  913. X.I next
  914. Xpointers.
  915. XThe value returned is a pointer to the first stanza in the list.
  916. X.PP
  917. X.I Profile_write_stanza
  918. Xwrites a stanza in a canonical form suitable for input by
  919. X.IR profile_read_stanza .
  920. XMarkers are output one to a line.
  921. XEach binding is indented by a single tab.
  922. XNames and values are separated, one from the other,
  923. Xby a single blank.
  924. X.PP
  925. X.I Profile_write_profile
  926. Xwrites all the stanzas in a linked list by applying
  927. X.I profile_write_stanza
  928. Xto each stanza in the list.
  929. XThe list need not be doubly linked.
  930. X.PP
  931. X.I Profile_free_stanza
  932. Xfrees all storage associated with a stanza.
  933. X.PP
  934. X.I Profile_has_marker
  935. Xsearches the marker list of a stanza for a match to the given marker,
  936. X.IR m .
  937. XA pointer to the marker is returned on success and
  938. X.B NULL
  939. Xon failure.
  940. X.PP
  941. X.I Profile_has_stanza
  942. Xsearches a linked list of stanzas for a stanza that has all the
  943. Xmarkers in
  944. X.I marker.
  945. X.I Marker 
  946. Xmust be terminated by a null entry.
  947. X.PP
  948. X.I Profile_has_binding
  949. Xsearches the binding list of a stanza
  950. Xfor a binding with a match to the given name.
  951. XA pointer to the binding is returned on success and
  952. X.B NULL
  953. Xon failure.
  954. X.PP
  955. XThe following routines are useful for constructing stanzas on the fly.
  956. X.I Profile_stanza_space
  957. Xallocates storage for a stanza.
  958. X.I Profile_marker_space
  959. Xallocates storage for a marker including sufficient space for
  960. X.I n
  961. Xcharacters of text plus a terminating null byte.
  962. X.I Profile_binding_space
  963. Xallocates storage for a binding including sufficient space for
  964. X.I n
  965. Xcharacters of name text plus a terminating null byte.
  966. X.I Profile_value_space
  967. Xallocates storage for a value.
  968. XIf
  969. X.I n
  970. Xis positive and non-zero the component
  971. X.IR value . s
  972. Xis initialized as a
  973. X.IR n +1
  974. Xcharacter array.
  975. XAll of the above routines return a pointer on success and
  976. X.B NULL
  977. Xon failure.
  978. XAll storage is zero filled.
  979. XThe routine
  980. X.IR free (3)
  981. Xmay be safely used to release storage allocated by these routines.
  982. X.SH AUTHOR
  983. XMichael Gorlick, TRW
  984. X.SH SEE ALSO
  985. Xmalloc(3), profile(5)
  986. !FaR!OuT!
  987. if [ ! -d libprofile ]
  988. then
  989.     mkdir libprofile
  990.     echo mkdir libprofile
  991. fi
  992. echo x - libprofile/profile.5
  993. sed -e 's/^X//' > libprofile/profile.5 << '!FaR!OuT!'
  994. X.\" @(#)profile.5    1.1 (TRW) 6/11/84
  995. X.TH PROFILE 5 TRW
  996. X.UC 4
  997. X.SH NAME
  998. Xprofile \- configuration file format
  999. X.SH SYNOPSIS
  1000. X.B #include <local/profile.h>
  1001. X.SH DESCRIPTION
  1002. X.I Profile
  1003. Xis a general purpose configuration file facility.
  1004. X.PP
  1005. XEach profile is an ASCII file containing a sequence of one or more
  1006. X.IR stanzas .
  1007. XEach stanza in turn consists of a sequence of
  1008. X.I markers
  1009. Xfollowed by a sequence of
  1010. X.IR bindings .
  1011. XThe characters `{' (left brace) and `}' (right brace)
  1012. Xdelimit the beginning and end respectively of the stanza bindings.
  1013. XEach binding consists of a name
  1014. Xfollowed by an optional sequence of values. 
  1015. X.SH MARKERS
  1016. XMarkers are arbitrary patterns in the style of
  1017. X.IR glob (3)
  1018. Xdelimited by white space.
  1019. XThe list of markers may be empty.
  1020. XThere is no limit to the number of markers.
  1021. XExamples of markers are:
  1022. X.nf
  1023. X
  1024. X    queue
  1025. X    /usr/lib
  1026. X    1776
  1027. X    a_long_marker
  1028. X    file[0-9]*.?
  1029. X.fi
  1030. X.SH BINDINGS
  1031. XBindings are the association of names with values.
  1032. XThere is one binding to a line each consisting of a name followed
  1033. Xby an optional sequence of values.
  1034. XNames and values are separated,
  1035. Xone from the other,
  1036. Xby blanks or tabs.
  1037. XHere a newline preceded by a backslash is equivalent to a blank.
  1038. XThe list of bindings may be empty.
  1039. XThere is no limit to the number of bindings.
  1040. XBy convention each binding is indented by a single tab.
  1041. X.SH NAMES
  1042. XNames are arbitrary patterns in the style of
  1043. X.IR glob (3)
  1044. Xdelimited by white space.
  1045. X.SH VALUES
  1046. XValues are
  1047. Xinteger,
  1048. Xreal,
  1049. Xoctal,
  1050. Xhex,
  1051. Xcharacter,
  1052. Xor
  1053. Xstring
  1054. Xconstants.
  1055. XArbitrary text,
  1056. Xnot recognizably one of the aforementioned types,
  1057. Xis classified as
  1058. X.I other
  1059. Xand is a legitimate value.
  1060. X.TP
  1061. Xinteger
  1062. XA sequence of digits optionally preceded by a minus sign.
  1063. XEvery integer constant is taken to be long.
  1064. X.TP
  1065. Xfloating
  1066. XA floating constant consists of an optional minus sign,
  1067. Xan integer part
  1068. Xa decimal point,
  1069. Xa fraction part,
  1070. Xan
  1071. X.B e
  1072. Xor
  1073. X.BR E ,
  1074. Xand an optionally signed integer exponent.
  1075. XThe integer and fraction parts both consist of a sequence of digits.
  1076. XEither the integer part or the fraction part (not both)
  1077. Xmay be missing;
  1078. Xeither the decimal point or the
  1079. X.B e
  1080. Xand the exponent (not both) may be missing.
  1081. XEvery floating constant is taken to be double-precision.
  1082. X.TP
  1083. Xhex
  1084. XA sequence of hexidecimal digits preceded by
  1085. X.B 0x
  1086. Xor
  1087. X.BR 0X .
  1088. XThe hexidecimal digits are 0-9, a-e and A-F.
  1089. XEvery hex constant is taken to be long.
  1090. X.TP
  1091. Xoctal
  1092. XA sequence of octal digits preceded by
  1093. X.B 0o
  1094. Xor
  1095. X.B 0O 
  1096. X(digit zero followed by a letter o).
  1097. XThe octal digits are 0-7.
  1098. XEvery octal constant is taken to be long.
  1099. X.TP
  1100. Xcharacter
  1101. XA character constant is a character enclosed in single quotes.
  1102. XCertain non-graphic characters,
  1103. Xthe single quote ',
  1104. Xthe caret ^ and
  1105. Xthe backslash \\,
  1106. Xmay be represented according to the following table of escape sequences:
  1107. X.ta 1i +\w'carriage return  'u
  1108. X.nf
  1109. X
  1110. X     newline    \\n
  1111. X    horizontal tab    \\t
  1112. X    backspace    \\b
  1113. X    carriage return    \\r
  1114. X    form feed    \\f
  1115. X    escape    \\e
  1116. X    backslash    \\\\
  1117. X    single quote    \\'
  1118. X    caret    \\^
  1119. X    control-@    ^@
  1120. X    control-A    ^A
  1121. X    ...    ...
  1122. X    control-Z    ^Z
  1123. X    control-[    ^[
  1124. X    control-\\    ^\\
  1125. X    control-^    ^^
  1126. X    control-_    ^_
  1127. X    delete    ^?
  1128. X    bit pattern    \\\fIddd\fR
  1129. X
  1130. X.fi
  1131. X.DT
  1132. XThe escape \\\fIddd\fR
  1133. Xconsists of the backslash followed by 1, 2, or 3 octal digits
  1134. Xwhich are taken to specify the value of the desired character.
  1135. XIf the character following a backslash (caret) is not one of those
  1136. Xspecified, the backslash (caret) is ignored.
  1137. X.TP
  1138. Xstring
  1139. XA string is a sequence of characters surrounded by double quotes, as in
  1140. X\fB"..."\fR.
  1141. XIn a string,
  1142. Xthe double quote character \fB"\fR must be preceded by a \\;
  1143. Xin addition,
  1144. Xthe same escapes as described for character constants may be used.
  1145. X.PP
  1146. XExamples of values are:
  1147. X.nf
  1148. X
  1149. X    7
  1150. X    -1.293e3
  1151. X    0x10a5
  1152. X    0o1273
  1153. X    'x'
  1154. X    "a string"
  1155. X    an_other_value
  1156. X.fi
  1157. X.SH COMMENTS
  1158. XComments may appear anywhere within a profile.
  1159. XThey are introduced by the character `#' and are terminated by
  1160. Xthe succeeding newline.
  1161. X.SH EXAMPLES
  1162. XThe empty stanza.
  1163. X.nf
  1164. X
  1165. X{
  1166. X}
  1167. X.fi
  1168. X.PP
  1169. XA stanza in the configuration file of a fictitious network server.
  1170. X.nf
  1171. X.ta \w'queue 'u +\w'cost_per_packet 'u +\w'0o125 0x1af  'u
  1172. X
  1173. Xqueue net*
  1174. X{
  1175. X    priority    7    # integer
  1176. X    expect    "who is it"    # string
  1177. X    send    '?'    # character
  1178. X    flags[0-9]    0o125 0x1af     # octal and hex
  1179. X    cost_per_packet    0.28    # floating
  1180. X    device    /dev/net    # other
  1181. X    homebrew        # a name with no associated value
  1182. X}    
  1183. X.fi
  1184. X.DT
  1185. X.PP
  1186. XA password file entry recast as a stanza.
  1187. X.nf
  1188. X.ta \w'brown 'u +\w'password 'u
  1189. X
  1190. Xbrown
  1191. X{
  1192. X    password    /bObOZtyGclMV
  1193. X    userid    225
  1194. X    groupid    30
  1195. X    home    /home/brown
  1196. X    shell    /bin/csh
  1197. X}
  1198. X.fi
  1199. X.DT
  1200. X.PP
  1201. XA termcap entry recast as a stanza.
  1202. X.nf
  1203. X.ta \w'adm3a 'u +\w'mm 'u
  1204. X
  1205. Xadm3a
  1206. X{
  1207. X    fullname "lsi adm3a"
  1208. X    am
  1209. X    bs
  1210. X    cm    "\\e=%+ %+ "
  1211. X    cl    "1^Z"
  1212. X    co    80
  1213. X    li    24
  1214. X    ho    '^^'
  1215. X    ma    "^K^P"
  1216. X    nd    '^L'
  1217. X    up    '^K'
  1218. X}
  1219. X.fi
  1220. X.SH AUTHOR
  1221. XMichael Gorlick, TRW
  1222. X.SH SEE ALSO
  1223. Xglob(3), profile(3)
  1224. !FaR!OuT!
  1225. if [ ! -d libprofile ]
  1226. then
  1227.     mkdir libprofile
  1228.     echo mkdir libprofile
  1229. fi
  1230. echo x - libprofile/profile.h
  1231. sed -e 's/^X//' > libprofile/profile.h << '!FaR!OuT!'
  1232. X/* @(#)profile.h    1.1 (TRW) 1/14/86 */
  1233. Xtypedef struct PROFILE_VALUE {
  1234. X    char class;
  1235. X    union {
  1236. X        long int i;
  1237. X        double f;
  1238. X        char c;
  1239. X        char *s;
  1240. X    } value;
  1241. X    struct PROFILE_VALUE *previous;
  1242. X    struct PROFILE_VALUE *next;
  1243. X} PROFILE_VALUE;
  1244. X
  1245. Xtypedef struct PROFILE_BINDING {
  1246. X    char *name;
  1247. X    PROFILE_VALUE *value;
  1248. X    struct PROFILE_BINDING *previous;
  1249. X    struct PROFILE_BINDING *next;
  1250. X} PROFILE_BINDING;
  1251. X
  1252. Xtypedef struct PROFILE_MARKER {
  1253. X    char *text;
  1254. X    struct PROFILE_MARKER *previous;
  1255. X    struct PROFILE_MARKER *next;
  1256. X} PROFILE_MARKER;
  1257. X
  1258. Xtypedef struct PROFILE_STANZA {
  1259. X    PROFILE_MARKER *marker;
  1260. X    PROFILE_BINDING *binding;
  1261. X    struct PROFILE_STANZA *previous;
  1262. X    struct PROFILE_STANZA *next;
  1263. X} PROFILE_STANZA;
  1264. X
  1265. X/* classes */
  1266. X#define PROFILE_INTEGER 01
  1267. X#define PROFILE_FLOAT 02
  1268. X#define PROFILE_STRING 03
  1269. X#define PROFILE_CHARACTER 04
  1270. X#define PROFILE_OTHER 05
  1271. X#define PROFILE_OCTAL 06
  1272. X#define PROFILE_HEX 07
  1273. X
  1274. X/* no single lexical element may exceed this size in characters */
  1275. X#define PROFILE_MAX_TEXT 255
  1276. X
  1277. XPROFILE_STANZA *profile_read_stanza();
  1278. XPROFILE_STANZA *profile_read_profile();
  1279. XPROFILE_MARKER *profile_has_marker();
  1280. XPROFILE_STANZA *profile_has_stanza();
  1281. XPROFILE_BINDING *profile_has_binding();
  1282. XPROFILE_STANZA *profile_stanza_space();
  1283. XPROFILE_MARKER *profile_marker_space();
  1284. XPROFILE_BINDING *profile_binding_space();
  1285. XPROFILE_VALUE *profile_value_space();
  1286. !FaR!OuT!
  1287. if [ ! -d libprofile ]
  1288. then
  1289.     mkdir libprofile
  1290.     echo mkdir libprofile
  1291. fi
  1292. echo x - libprofile/read.c
  1293. sed -e 's/^X//' > libprofile/read.c << '!FaR!OuT!'
  1294. Xstatic char *trwsccs = "@(#)read.c    1.1 (TRW) 1/14/86";
  1295. X#include <stdio.h>
  1296. X#include <ctype.h>
  1297. X#include "profile.h"
  1298. X
  1299. X#define isoctal(d) ('0' <= d && d <= '7')
  1300. X#define ishex(x) (isdigit(x) || ('a' <= x && x <= 'f') || ('A' <= x && x <= 'F'))
  1301. X#define isprime(c) (c == '\'')
  1302. X#define isbackslash(c) (c == '\\')
  1303. X#define iscaret(c) (c == '^')
  1304. X
  1305. Xextern char *strcpy();
  1306. Xextern PROFILE_STANZA *profile_stanza_space();
  1307. Xextern PROFILE_MARKER *profile_marker_space();
  1308. Xextern PROFILE_BINDING *profile_binding_space();
  1309. Xextern PROFILE_VALUE *profile_value_space();
  1310. X
  1311. Xstatic PROFILE_BINDING *get_binding();
  1312. Xstatic PROFILE_BINDING *get_bindings();
  1313. Xstatic PROFILE_MARKER *get_marker();
  1314. Xstatic PROFILE_MARKER *get_markers();
  1315. Xstatic PROFILE_VALUE *get_value();
  1316. Xstatic PROFILE_VALUE *get_values();
  1317. Xstatic char parse_character();
  1318. Xstatic PROFILE_VALUE *parse_value();
  1319. X
  1320. XPROFILE_STANZA *profile_read_stanza (f)
  1321. XFILE *f;
  1322. X{
  1323. X    PROFILE_STANZA *stanza;
  1324. X
  1325. X    stanza = profile_stanza_space();
  1326. X    if (stanza == NULL)
  1327. X        return(NULL);
  1328. X    stanza->marker = get_markers(f);
  1329. X    if (get_open_bindings(f))
  1330. X        stanza->binding = get_bindings(f);
  1331. X    else {
  1332. X        profile_free_stanza(stanza);
  1333. X        return(NULL);
  1334. X    }
  1335. X    if (get_close_bindings(f))
  1336. X        return(stanza);
  1337. X    else {
  1338. X        profile_free_stanza(stanza);
  1339. X        return(NULL);
  1340. X    }
  1341. X}
  1342. X
  1343. X/* Returns the list of markers at the head of a stanza. */
  1344. Xstatic PROFILE_MARKER *get_markers (f)
  1345. XFILE *f;
  1346. X{
  1347. X    PROFILE_MARKER *head, *tail, *m;
  1348. X
  1349. X    head = tail = NULL;
  1350. X    while (m = get_marker(f))
  1351. X        if (tail) {
  1352. X            tail->next = m;
  1353. X            m->previous = tail;
  1354. X            tail = m;
  1355. X        } else
  1356. X            head = tail = m;
  1357. X    return(head);
  1358. X}
  1359. X
  1360. X/* Returns the next marker from the head of the stanza. */
  1361. Xstatic PROFILE_MARKER *get_marker (f)
  1362. XFILE *f;
  1363. X{
  1364. X    int n;
  1365. X    PROFILE_MARKER *m;
  1366. X    char scratch[PROFILE_MAX_TEXT+1];
  1367. X
  1368. X    for (;;)
  1369. X        if (n = get_name_text(f, scratch)) {
  1370. X            if ((m = profile_marker_space(n)) == NULL)
  1371. X                return(NULL);
  1372. X            strcpy(m->text, scratch);
  1373. X            return(m);
  1374. X        } else if (get_end_of_line(f))
  1375. X            continue;
  1376. X        else
  1377. X            return(NULL);
  1378. X}
  1379. X
  1380. X/* Returns the list of bindings in the body of the stanza. */
  1381. Xstatic PROFILE_BINDING *get_bindings (f)
  1382. XFILE *f;
  1383. X{
  1384. X    PROFILE_BINDING *head, *tail, *b;
  1385. X
  1386. X    head = tail = NULL;
  1387. X    while (b = get_binding(f))
  1388. X        if (tail) {
  1389. X            tail->next = b;
  1390. X            b->previous = tail;
  1391. X            tail = b;
  1392. X        } else
  1393. X            head = tail = b;
  1394. X    return(head);
  1395. X}
  1396. X
  1397. X/* Returns the next binding in the body of the stanza. */
  1398. Xstatic PROFILE_BINDING *get_binding (f)
  1399. XFILE *f;
  1400. X{
  1401. X    int n;
  1402. X    PROFILE_BINDING *b;
  1403. X    char scratch[PROFILE_MAX_TEXT+1];
  1404. X
  1405. X    for (;;)
  1406. X        if (n = get_name_text(f, scratch)) {
  1407. X            if ((b = profile_binding_space(n)) == NULL)
  1408. X                return(NULL);
  1409. X            strcpy(b->name, scratch);
  1410. X            break;
  1411. X        } else if (get_end_of_line(f))
  1412. X            continue;
  1413. X        else
  1414. X            return(NULL);
  1415. X    b->value = get_values(f);
  1416. X    return(b);
  1417. X}
  1418. X
  1419. X/* Returns the list of values following the name of the binding. */
  1420. Xstatic PROFILE_VALUE *get_values (f)
  1421. XFILE *f;
  1422. X{
  1423. X    PROFILE_VALUE *head, *tail, *v;
  1424. X
  1425. X    head = tail = NULL;
  1426. X    while (v = get_value(f))
  1427. X        if (tail) {
  1428. X            tail->next = v;
  1429. X            v->previous = tail;
  1430. X            tail = v;
  1431. X        } else
  1432. X            head = tail = v;
  1433. X    return(head);
  1434. X}
  1435. X
  1436. X/* Returns the next value in the binding. */
  1437. Xstatic PROFILE_VALUE *get_value (f)
  1438. XFILE *f;
  1439. X{
  1440. X    char text[PROFILE_MAX_TEXT+1];
  1441. X    int n;
  1442. X
  1443. X    for (;;)
  1444. X        if (n = get_value_text(f, text))
  1445. X            return(parse_value(text, n));
  1446. X        else if (get_end_of_line(f))
  1447. X            return(NULL);
  1448. X        else
  1449. X            return(NULL);
  1450. X}
  1451. X
  1452. X/*
  1453. X * Reads the text of the next value (if any) in the binding.  Returns
  1454. X * the length of the literal text in characters.
  1455. X */
  1456. Xstatic int get_value_text (f, text)
  1457. XFILE *f;
  1458. Xchar *text;
  1459. X{
  1460. X    register int c;
  1461. X    char *s = text;
  1462. X
  1463. X    while ((c = getc(f)) != EOF)
  1464. X        switch (c) {
  1465. X        case '\b': case '\f':
  1466. X        case '\r': case '\t': case ' ':
  1467. X            /* white space terminates any text gathered so far */
  1468. X            if (s > text) {
  1469. X                *s = '\0';
  1470. X                return(s - text);
  1471. X            }
  1472. X            continue;
  1473. X
  1474. X        case '\n':
  1475. X            /* newline terminates a binding */
  1476. X            ungetc(c, f);
  1477. X            *s = '\0';
  1478. X            return(s - text);
  1479. X
  1480. X        case '#':
  1481. X            /* gobble up the comment */
  1482. X            while ((c = getc(f)) != EOF && c != '\n')
  1483. X                continue;
  1484. X            if (c == '\n')
  1485. X                ungetc(c, f);
  1486. X            *s = '\0';
  1487. X            return(s - text);
  1488. X
  1489. X        case '{': case '}':
  1490. X            ungetc(c, f);
  1491. X            *s = '\0';
  1492. X            return(s - text);
  1493. X
  1494. X        case '"':        /* string quotes */
  1495. X            ungetc(c, f);
  1496. X            if (s > text) {
  1497. X                *s = '\0';
  1498. X                return(s - text);
  1499. X            } else
  1500. X                return(get_string(f, s));
  1501. X
  1502. X        case '\'':        /* character quotes */
  1503. X            ungetc(c, f);
  1504. X            if (s > text) {
  1505. X                *s = '\0';
  1506. X                return(s - text);
  1507. X            } else
  1508. X                return(get_character(f, s));
  1509. X
  1510. X        case '\\':        /* newline escape */
  1511. X            c = getc(f);
  1512. X            if (c == '\n') {
  1513. X                if (s > text) {
  1514. X                    *s = '\0';
  1515. X                    return(s - text);
  1516. X                }
  1517. X                continue;    /* just like a blank */
  1518. X            }
  1519. X            ungetc(c, f);
  1520. X            if (s < &text[PROFILE_MAX_TEXT])
  1521. X                *s++ = '\\';
  1522. X            continue;
  1523. X
  1524. X        default:
  1525. X            if (s < &text[PROFILE_MAX_TEXT])
  1526. X                *s++ = c;
  1527. X            continue;
  1528. X        }
  1529. X    *s = '\0';
  1530. X    return(s - text);
  1531. X}
  1532. X
  1533. X/* Digests the raw value text returning a new value structure. */
  1534. Xstatic PROFILE_VALUE *parse_value (s, length)
  1535. Xchar *s;        /* literal text */
  1536. Xint length;        /* in characters */
  1537. X{
  1538. X    PROFILE_VALUE *v;
  1539. X
  1540. X    if (is_integer(s)) {
  1541. X        if ((v = profile_value_space(0)) == NULL)
  1542. X            return(NULL);
  1543. X        v->class = PROFILE_INTEGER;
  1544. X        sscanf(s, "%D", &v->value.i);
  1545. X    } else if (is_octal(s)) {
  1546. X        if ((v = profile_value_space(0)) == NULL)
  1547. X            return(NULL);
  1548. X        v->class = PROFILE_OCTAL;
  1549. X        /* skip the `0o' prefix */
  1550. X        sscanf(s+2, "%O", &v->value.i);
  1551. X    } else if (is_hex(s)) {
  1552. X        if ((v = profile_value_space(0)) == NULL)
  1553. X            return(NULL);
  1554. X        v->class = PROFILE_HEX;
  1555. X        /* skip the `0x' prefix */
  1556. X        sscanf(s+2, "%X", &v->value.i);
  1557. X    } else if (is_string(s)) {
  1558. X        /* be careful when dealing with the empty string "" */
  1559. X        if ((v = profile_value_space(length > 2 ? length - 2 : 1)) == NULL)
  1560. X            return(NULL);
  1561. X        v->class = PROFILE_STRING;
  1562. X        /* erase the terminating double quote */
  1563. X        s[length - 1] = '\0';
  1564. X        /* skip past the initial quote */
  1565. X        parse_string(s + 1, v->value.s);
  1566. X    } else if (is_character(s)) {
  1567. X        if ((v = profile_value_space(0)) == NULL)
  1568. X            return(NULL);
  1569. X        v->class = PROFILE_CHARACTER;
  1570. X        /* erase the end single quote */
  1571. X        s[length - 1] = '\0';
  1572. X        v->value.c = parse_character(s + 1);
  1573. X    } else if (is_float(s)) {
  1574. X        if ((v = profile_value_space(0)) == NULL)
  1575. X            return(NULL);
  1576. X        v->class = PROFILE_FLOAT;
  1577. X        sscanf(s, "%E", &v->value.f);
  1578. X    } else {
  1579. X        if ((v = profile_value_space(length)) == NULL)
  1580. X            return(NULL);
  1581. X        v->class = PROFILE_OTHER;
  1582. X        strcpy(v->value.s, s);
  1583. X    }
  1584. X    return(v);
  1585. X}
  1586. X
  1587. X/* Converts a string literal to the internal representation. */
  1588. Xstatic parse_string (source, result)
  1589. Xchar *source;
  1590. Xchar *result;
  1591. X{
  1592. X    for (; *source; source++)
  1593. X        if (*source == '\\')
  1594. X            switch (*++source) {
  1595. X            case 'b':            /* backspace */
  1596. X                *result++ = '\b';
  1597. X                continue;
  1598. X            case 'f':            /* formfeed */
  1599. X                *result++ = '\f';
  1600. X                continue;
  1601. X            case 'n':            /* newline */
  1602. X                *result++ = '\n';
  1603. X                continue;
  1604. X            case 'r':            /* carriage return */
  1605. X                *result++ = '\r';
  1606. X                continue;
  1607. X            case 't':            /* horizontal tab */
  1608. X                *result++ = '\t';
  1609. X                continue;
  1610. X            case '\'':            /* single quote */
  1611. X                *result++ = '\'';
  1612. X                continue;
  1613. X            case '"':            /* double quote */
  1614. X                *result++ = '"';
  1615. X                continue;
  1616. X            case '\\':            /* backslash */
  1617. X                *result++ = '\\';
  1618. X                continue;            
  1619. X            case '^':            /* caret */
  1620. X                *result++ = '^';
  1621. X                continue;
  1622. X            case '0': case '1':        /* octal constant */
  1623. X            case '2': case '3':
  1624. X            case '4': case '5':
  1625. X            case '6': case '7':
  1626. X                source += parse_octal(source, result) - 1;
  1627. X                result++;
  1628. X                continue;
  1629. X            default:
  1630. X                *result++ = *source;    /* ignore backslash */
  1631. X            }
  1632. X        else if (*source == '^') {    /* control escape */
  1633. X            char c = *++source;
  1634. X            *result++ = ('@' <= c && c <= '_') ? c - '@' :
  1635. X                    (c == '?') ? '\177' : c;
  1636. X            continue;
  1637. X        } else
  1638. X            *result++ = *source;
  1639. X    *result = '\0';
  1640. X}
  1641. X
  1642. X/* Converts a character literal to the internal representation. */
  1643. Xstatic char parse_character (source)
  1644. Xchar *source;
  1645. X{
  1646. X    char c;
  1647. X
  1648. X    if (*source == '\\')
  1649. X        switch (*++source) {
  1650. X        case 'b':            /* backspace */
  1651. X            return('\b');
  1652. X        case 'f':            /* formfeed */
  1653. X            return('\f');
  1654. X        case 'n':            /* newline */
  1655. X            return('\n');
  1656. X        case 'r':            /* carriage return */
  1657. X            return('\r');
  1658. X        case 't':            /* horizontal tab */
  1659. X            return('\t');
  1660. X        case '\'':            /* single quote */
  1661. X            return('\'');
  1662. X        case '\\':            /* backslash */
  1663. X            return('\\');
  1664. X        case '^':
  1665. X            return('^');
  1666. X        case '0': case '1':        /* octal constant */
  1667. X        case '2': case '3':
  1668. X        case '4': case '5':
  1669. X        case '6': case '7':
  1670. X            parse_octal(source, &c);
  1671. X            return(c);
  1672. X        default:
  1673. X            return(*source);    /* ignore backslash */
  1674. X        }
  1675. X    else if (*source == '^') {    /* control escape */
  1676. X        c = *++source;
  1677. X        return(('@' <= c && c <= '_') ? c - '@' : (c == '?') ? '\177' : c);
  1678. X    } else
  1679. X        return(*source);
  1680. X}
  1681. X
  1682. X/* Converts an octal escape `\ddd' to its byte representation. */
  1683. Xstatic int parse_octal (source, result)
  1684. Xchar *source;
  1685. Xchar *result;
  1686. X{
  1687. X    int count;
  1688. X    char byte = '\0';
  1689. X    char digit;
  1690. X
  1691. X    for (count = 1; count <= 3; count++) {
  1692. X        digit = *source++;
  1693. X        if ('0' <= digit && digit <= '7')
  1694. X            byte = (byte * 8) + (digit - '0');
  1695. X        else
  1696. X            break;
  1697. X    }
  1698. X    *result = byte;
  1699. X    return(count);
  1700. X}
  1701. X
  1702. X/*
  1703. X * Reads the literal text for markers and binding names.  Returns the
  1704. X * length in characters of the literal text.
  1705. X */
  1706. Xstatic int get_name_text (f, text)
  1707. XFILE *f;
  1708. Xchar *text;
  1709. X{
  1710. X    register int c;
  1711. X    char *s = text;
  1712. X
  1713. X    while ((c = getc(f)) != EOF)
  1714. X        switch (c) {
  1715. X        case '\b': case '\f':
  1716. X        case '\r': case '\t': case ' ':
  1717. X            /* white space terminates text gathered so far */
  1718. X            if (s > text) {
  1719. X                *s = '\0';
  1720. X                return(s - text);
  1721. X            }
  1722. X            continue;
  1723. X
  1724. X        case '\n':
  1725. X            ungetc(c, f);
  1726. X            *s = '\0';
  1727. X            return(s - text);
  1728. X
  1729. X        case '#':
  1730. X            /* gobble up the comment */
  1731. X            while ((c = getc(f)) != EOF && c != '\n')
  1732. X                continue;
  1733. X            if (c == '\n')
  1734. X                ungetc(c, f);
  1735. X            *s = '\0';
  1736. X            return(s - text);
  1737. X
  1738. X        case '{': case '}':
  1739. X            ungetc(c, f);
  1740. X            *s = '\0';
  1741. X            return(s - text);
  1742. X
  1743. X        case '[':
  1744. X            /* sets may contain embedded white space */
  1745. X            if (s + 1 < &text[PROFILE_MAX_TEXT]) {
  1746. X                *s++ = '[';
  1747. X                if ((c = getc(f)) != EOF)
  1748. X                *s++ = c;
  1749. X            }
  1750. X            while ((c = getc(f)) != EOF) {
  1751. X                if (s < &text[PROFILE_MAX_TEXT])
  1752. X                    *s++ = c;
  1753. X                if (c == ']')
  1754. X                    break;
  1755. X            }
  1756. X            continue;
  1757. X
  1758. X        case '\\':
  1759. X            c = getc(f);
  1760. X            if (c == '\n') {
  1761. X                if (s > text) {
  1762. X                    *s = '\0';
  1763. X                    return(s - text);
  1764. X                }
  1765. X                continue;    /* just like a blank */
  1766. X            }
  1767. X            ungetc(c, f);
  1768. X            if (s < &text[PROFILE_MAX_TEXT])
  1769. X                *s++ = '\\';
  1770. X            continue;
  1771. X
  1772. X        default:
  1773. X            if (s < &text[PROFILE_MAX_TEXT])
  1774. X                *s++ = c;
  1775. X            continue;
  1776. X        }
  1777. X    *s = '\0';
  1778. X    return(s - text);
  1779. X}
  1780. X
  1781. X/* Returns non-zero on end of line and zero otherwise. */
  1782. Xstatic int get_end_of_line (f)
  1783. XFILE *f;
  1784. X{
  1785. X    int c;
  1786. X
  1787. X    if ((c = getc(f)) == '\n')
  1788. X        return(1);
  1789. X    ungetc(c, f);
  1790. X    return(0);
  1791. X}
  1792. X
  1793. X/* Returns non-zero on seeing `{' and zero otherwise. */
  1794. Xstatic int get_open_bindings (f)
  1795. XFILE *f;
  1796. X{
  1797. X    int c;
  1798. X
  1799. X    if ((c = getc(f)) == '{')
  1800. X        return(1);
  1801. X    ungetc(c, f);
  1802. X    return(0);
  1803. X}
  1804. X
  1805. X/* Returns non-zero on seeing `}' and zero otherwise. */ 
  1806. Xstatic int get_close_bindings (f)
  1807. XFILE *f;
  1808. X{
  1809. X    int c;
  1810. X
  1811. X    if ((c = getc(f)) == '}')
  1812. X        return(1);
  1813. X    ungetc(c, f);
  1814. X    return(0);
  1815. X}
  1816. X
  1817. X/* Reads a string literal returning the length of the literal text in characters */
  1818. Xstatic int get_string (f, text)
  1819. XFILE *f;
  1820. Xchar *text;
  1821. X{
  1822. X    register int c;
  1823. X    char *s = text;
  1824. X
  1825. X    /* the first double quote is guaranteed */
  1826. X    *s++ = getc(f);
  1827. X    while ((c = getc(f)) != EOF)
  1828. X        switch (c) {
  1829. X        case '\\':
  1830. X            if (s < &text[PROFILE_MAX_TEXT])
  1831. X                *s++ = c;
  1832. X            c = getc(f);
  1833. X            if (c == EOF)
  1834. X                return(s - text);
  1835. X            else if (c == '\n') {
  1836. X                ungetc(c, f);
  1837. X                return(s - text);
  1838. X            } else if (s < &text[PROFILE_MAX_TEXT])
  1839. X                *s++ = c;
  1840. X            continue;
  1841. X
  1842. X        case '"':
  1843. X            if (s < &text[PROFILE_MAX_TEXT])
  1844. X                *s++ = c;
  1845. X            *s = '\0';
  1846. X            return(s - text);
  1847. X
  1848. X        case '\n':
  1849. X            ungetc(c, f);
  1850. X            *s = '\0';
  1851. X            return(s - text);
  1852. X
  1853. X        default:
  1854. X            if (s < &text[PROFILE_MAX_TEXT])
  1855. X                *s++ = c;
  1856. X            continue;
  1857. X        }
  1858. X    *s = '\0';
  1859. X    return(s - text);
  1860. X}
  1861. X
  1862. X/* Reads a character literal returning the length of the literal text in characters. */
  1863. Xstatic int get_character (f, text)
  1864. XFILE *f;
  1865. Xchar *text;
  1866. X{
  1867. X    register int c;
  1868. X    char *s = text;
  1869. X
  1870. X    /* the first single quote is guaranteed */
  1871. X    *s++ = getc(f);
  1872. X    while ((c = getc(f)) != EOF)
  1873. X        switch (c) {
  1874. X        case '\\':
  1875. X            if (s < &text[PROFILE_MAX_TEXT])
  1876. X                *s++ = c;
  1877. X            c = getc(f);
  1878. X            if (c == EOF)
  1879. X                return(s - text);
  1880. X            else if (c == '\n') {
  1881. X                ungetc(c, f);
  1882. X                return(s - text);
  1883. X            } else if (s < &text[PROFILE_MAX_TEXT])
  1884. X                *s++ = c;
  1885. X            continue;
  1886. X        case '\'':
  1887. X            if (s < &text[PROFILE_MAX_TEXT])
  1888. X                *s++ = c;
  1889. X            *s = '\0';
  1890. X            return(s - text);
  1891. X        case '\n':
  1892. X            ungetc(c, f);
  1893. X            *s = '\0';
  1894. X            return(s - text);
  1895. X        default:
  1896. X            if (s < &text[PROFILE_MAX_TEXT])
  1897. X                *s++ = c;
  1898. X            continue;
  1899. X        }
  1900. X    *s = '\0';
  1901. X    return(s - text);
  1902. X}
  1903. X
  1904. X/* all regular expressions below are in lex notation */
  1905. X
  1906. X/* returns non-zero iff -?[0-9]+ matches */
  1907. Xstatic int is_integer (s)
  1908. Xchar *s;
  1909. X{
  1910. X    char *x;
  1911. X
  1912. X    /* -? */
  1913. X    if (*s == '-')
  1914. X        s++;
  1915. X    /* [0-9]+ */
  1916. X    for (x = s; isdigit(*s); s++)
  1917. X        continue;
  1918. X    return(s > x && !*s);
  1919. X}
  1920. X
  1921. X/* returns non-zero iff 0[oO][0-7]+ matches */
  1922. Xstatic int is_octal (s)
  1923. Xchar *s;
  1924. X{
  1925. X    char *x;
  1926. X
  1927. X    /* 0 */
  1928. X    if (*s == '0')
  1929. X        s++;
  1930. X    else
  1931. X        return(0);
  1932. X    /* [oO] */
  1933. X    if (*s == 'o' || *s == 'O')
  1934. X        s++;
  1935. X    else
  1936. X        return(0);
  1937. X    /* [0-7]+ */
  1938. X    for (x = s; isoctal(*s); s++)
  1939. X        continue;
  1940. X    return(s > x && !*s);
  1941. X}
  1942. X
  1943. X/* returns non-zero iff 0[xX][0-9a-fA-F]+ matches */
  1944. Xstatic int is_hex (s)
  1945. Xchar *s;
  1946. X{
  1947. X    char *x;
  1948. X
  1949. X    /* 0 */
  1950. X    if (*s == '0')
  1951. X        s++;
  1952. X    else
  1953. X        return(0);
  1954. X    /* [xX] */
  1955. X    if (*s == 'x' || *s == 'X')
  1956. X        s++;
  1957. X    else
  1958. X        return(0);
  1959. X    /* [0-9a-fA-F]+ */
  1960. X    for (x = s; ishex(*s); s++)
  1961. X        continue;
  1962. X    return(s > x && !*s);
  1963. X}
  1964. X
  1965. X/* returns non-zero iff [eE][-+]?[0-9]+ matches */
  1966. Xstatic int is_exponent (s)
  1967. Xchar *s;
  1968. X{
  1969. X    char *x;
  1970. X
  1971. X    /* [eE] */
  1972. X    if (*s == 'e' || *s == 'E')
  1973. X        s++;
  1974. X    else
  1975. X        return(0);
  1976. X    /* [-+]? */
  1977. X    if (*s == '-' || *s == '+')
  1978. X        s++;
  1979. X    /* [0-9]+ */
  1980. X    for (x = s; isdigit(*s); s++)
  1981. X        continue;
  1982. X    return(s > x && !*s);
  1983. X}
  1984. X
  1985. Xstatic int is_float (s)
  1986. Xchar *s;
  1987. X{
  1988. X    return(is_integer_part_float(s) ||
  1989. X           is_fractional_part_float(s) ||
  1990. X           is_power_float(s));
  1991. X}
  1992. X
  1993. X/* returns non-zero iff -?[0-9]+"."[0-9]*({exponent})? matches */
  1994. Xstatic int is_integer_part_float (s)
  1995. Xchar *s;
  1996. X{
  1997. X    char *x;
  1998. X
  1999. X    /* -? */
  2000. X    if (*s == '-')
  2001. X        s++;
  2002. X    /* [0-9]+"." */
  2003. X    for (x = s; isdigit(*s); s++)
  2004. X        continue;
  2005. X    if (x == s || *s != '.')
  2006. X        return(0);
  2007. X    /* [0-9]* */
  2008. X    for (s++; isdigit(*s); s++)
  2009. X        continue;
  2010. X    /* ({exponent})? */
  2011. X    return(*s ? is_exponent(s) : 1);
  2012. X}
  2013. X
  2014. X/* returns non-zero iff -?"."[0-9]+({exponent})? matches */
  2015. Xstatic int is_fractional_part_float (s)
  2016. Xchar *s;
  2017. X{
  2018. X    char *x;
  2019. X
  2020. X    /* -? */
  2021. X    if (*s == '-')
  2022. X        s++;
  2023. X    /* "." */
  2024. X    if (*s == '.')
  2025. X        s++;
  2026. X    else
  2027. X        return(0);
  2028. X    /* [0-9]+({exponent})? */
  2029. X    for (x = s; isdigit(*s); s++)
  2030. X        continue;
  2031. X    return(s > x ? !*s || is_exponent(s) : 0);
  2032. X}
  2033. X
  2034. X/* returns non-zero iff -?[0-9]+{exponent} matches */
  2035. Xstatic int is_power_float (s)
  2036. Xchar *s;
  2037. X{
  2038. X    char *x;
  2039. X
  2040. X    /* -? */
  2041. X    if (*s == '-')
  2042. X        s++;
  2043. X    /* [0-9]+{exponent} */
  2044. X    for (x = s; isdigit(*s); s++)
  2045. X        continue;
  2046. X    return(s > x ? is_exponent(s) : 0);
  2047. X}
  2048. X
  2049. X/* returns non-zero iff '[^^\]' | '\^.' | '\\\\' | '\\'' | '\[0-7]{1-3}' matches */
  2050. Xstatic int is_character (s)
  2051. Xchar *s;
  2052. X{
  2053. X    char *x;
  2054. X
  2055. X    if (isprime(*s))
  2056. X        s++;
  2057. X    else
  2058. X        return(0);
  2059. X    if (isbackslash(*s)) {
  2060. X        s++;
  2061. X        if ((isbackslash(s[0]) || isprime(s[0]) || !isdigit(s[0])) &&
  2062. X            isprime(s[1]) && !s[2])
  2063. X            return(1);
  2064. X        for (x = s; isoctal(*s); s++)
  2065. X            continue;
  2066. X        return(x < s && s < (x+4) && isprime(s[0]) && !s[1]);
  2067. X    } else if (iscaret(*s))
  2068. X        s++;
  2069. X    return(isprint(s[0]) && isprime(s[1]) && !s[2]);
  2070. X}
  2071. X
  2072. X/* returns non-zero iff s is a string constant */
  2073. Xstatic int is_string (s)
  2074. Xchar *s;
  2075. X{
  2076. X    char *x;
  2077. X
  2078. X    if (*s != '"')
  2079. X        return(0);
  2080. X    for (s++; *s; s++) {
  2081. X        if (*s == '"')
  2082. X            return(!*++s);    /* quote must be followed by null */
  2083. X        if (isbackslash(*s) || iscaret(*s)) {
  2084. X            if (*++s)
  2085. X                continue;    /* legal escape */
  2086. X            return(0);    /* null follows \ or ^ */
  2087. X        }
  2088. X    }
  2089. X    return(0);
  2090. X}
  2091. X
  2092. X/*
  2093. X * read an entire profile, making a bidirectional
  2094. X * circularly linked list
  2095. X * returns pointer to the first stanza or NULL on error
  2096. X */
  2097. XPROFILE_STANZA *profile_read_profile(f)
  2098. XFILE *f;
  2099. X{
  2100. X    PROFILE_STANZA *head = NULL;
  2101. X    PROFILE_STANZA *tail = NULL;
  2102. X    PROFILE_STANZA *x = NULL;
  2103. X
  2104. X    while ((x = profile_read_stanza(f)) != NULL) {
  2105. X        if (head == NULL)
  2106. X            head = tail = x;
  2107. X        else {
  2108. X            tail->next = x; 
  2109. X            x->previous = tail;
  2110. X            tail = x;
  2111. X        }
  2112. X    }
  2113. X    if (head != NULL) { 
  2114. X        tail->next = head;
  2115. X        head->previous = tail;
  2116. X    }
  2117. X    return(head);
  2118. X}
  2119. !FaR!OuT!
  2120. if [ ! -d libprofile ]
  2121. then
  2122.     mkdir libprofile
  2123.     echo mkdir libprofile
  2124. fi
  2125. echo x - libprofile/space.c
  2126. sed -e 's/^X//' > libprofile/space.c << '!FaR!OuT!'
  2127. Xstatic char *trwsccs = "@(#)space.c    1.1 (TRW) 1/14/86";
  2128. X#include "profile.h"
  2129. X
  2130. Xextern char *calloc();
  2131. X
  2132. XPROFILE_STANZA *profile_stanza_space ()
  2133. X{
  2134. X    return((PROFILE_STANZA *)calloc(1, sizeof(PROFILE_STANZA)));
  2135. X}
  2136. X
  2137. XPROFILE_MARKER *profile_marker_space (n)
  2138. Xint n;
  2139. X{
  2140. X    char *space;
  2141. X    PROFILE_MARKER *m = (PROFILE_MARKER *)0;
  2142. X
  2143. X    if (space = calloc(1, sizeof(PROFILE_MARKER) + n + 1)) {
  2144. X        m = (PROFILE_MARKER *)space;
  2145. X        m->text = space + sizeof(PROFILE_MARKER);
  2146. X    }
  2147. X    return(m);
  2148. X}
  2149. X
  2150. XPROFILE_BINDING *profile_binding_space (n)
  2151. Xint n;        /* length of binding name in characters */
  2152. X{
  2153. X    char *space;
  2154. X    PROFILE_BINDING *b = (PROFILE_BINDING *)0;
  2155. X
  2156. X    if (space = calloc(1, sizeof(PROFILE_BINDING) + n + 1)) {
  2157. X        b = (PROFILE_BINDING *)space;
  2158. X        b->name = space + sizeof(PROFILE_BINDING);
  2159. X    }
  2160. X    return(b);
  2161. X}
  2162. X
  2163. XPROFILE_VALUE *profile_value_space (n)
  2164. Xint n;
  2165. X{
  2166. X    char *space;
  2167. X    PROFILE_VALUE *v = (PROFILE_VALUE *)0;
  2168. X
  2169. X    if (n > 0) {
  2170. X        if (space = calloc(1, sizeof(PROFILE_VALUE) + n + 1)) {
  2171. X            v = (PROFILE_VALUE *)space;
  2172. X            v->value.s = space + sizeof(PROFILE_VALUE);
  2173. X        }
  2174. X    } else
  2175. X        v = (PROFILE_VALUE *)calloc(1, sizeof(PROFILE_VALUE));
  2176. X    return(v);
  2177. X}
  2178. !FaR!OuT!
  2179. if [ ! -d libprofile ]
  2180. then
  2181.     mkdir libprofile
  2182.     echo mkdir libprofile
  2183. fi
  2184. echo x - libprofile/write.c
  2185. sed -e 's/^X//' > libprofile/write.c << '!FaR!OuT!'
  2186. Xstatic char *trwsccs = "@(#)write.c    1.1 (TRW) 1/14/86";
  2187. X#include <stdio.h>
  2188. X#include <ctype.h>
  2189. X#include "profile.h"
  2190. X
  2191. Xprofile_write_stanza (f, s)
  2192. XFILE *f;
  2193. XPROFILE_STANZA *s;
  2194. X{
  2195. X    write_markers(f, s->marker);
  2196. X    fprintf(f, "{\n");
  2197. X    write_bindings(f, s->binding);
  2198. X    fprintf(f, "}\n");
  2199. X}
  2200. X
  2201. Xstatic write_markers (f, m)
  2202. XFILE *f;
  2203. XPROFILE_MARKER *m;
  2204. X{
  2205. X    for (; m; m = m->next)
  2206. X        fprintf(f, "%s\n", m->text);
  2207. X}
  2208. X
  2209. Xstatic write_bindings (f, b)
  2210. XFILE *f;
  2211. XPROFILE_BINDING *b;
  2212. X{
  2213. X    while (b) {
  2214. X        fprintf(f, "\t%s", b->name);
  2215. X        write_values(f, b->value);
  2216. X        fputc('\n', f);
  2217. X        b = b->next;
  2218. X    }
  2219. X}
  2220. X
  2221. Xstatic write_values (f, v)
  2222. XFILE *f;
  2223. XPROFILE_VALUE *v;
  2224. X{
  2225. X    char scratch[PROFILE_MAX_TEXT+1];
  2226. X
  2227. X    for (; v; v = v->next)
  2228. X        switch (v->class) {
  2229. X        case PROFILE_INTEGER:
  2230. X            fprintf(f, " %D", v->value.i);
  2231. X            continue;
  2232. X        case PROFILE_FLOAT:
  2233. X            fprintf(f, " %G", v->value.f);
  2234. X            continue;
  2235. X        case PROFILE_STRING:
  2236. X            unparse_string(v->value.s, scratch);
  2237. X            fprintf(f, " \"%s\"", scratch);
  2238. X            continue;
  2239. X        case PROFILE_CHARACTER:
  2240. X            unparse_character(v->value.c, scratch);
  2241. X            fprintf(f, " '%s'", scratch);
  2242. X            continue;
  2243. X        case PROFILE_OCTAL:
  2244. X            fprintf(f, " 0o%O", v->value.i);
  2245. X            continue;
  2246. X        case PROFILE_HEX:
  2247. X            fprintf(f, " 0x%X", v->value.i);
  2248. X            continue;
  2249. X        case PROFILE_OTHER:
  2250. X            fprintf(f, " %s", v->value.s);
  2251. X            continue;
  2252. X        }
  2253. X}
  2254. X
  2255. Xstatic int unparse_string (from, to)
  2256. Xchar *from;
  2257. Xchar *to;
  2258. X{
  2259. X    char *x = to;
  2260. X
  2261. X    for (; *from; from++)
  2262. X        switch (*from) {
  2263. X        case '\b':        /* backspace */
  2264. X            *x++ = '\\';
  2265. X            *x++ = 'b';
  2266. X            continue;
  2267. X        case '\f':        /* formfeed */
  2268. X            *x++ = '\\';
  2269. X            *x++ = 'f';
  2270. X            continue;
  2271. X        case '\n':        /* newline */
  2272. X            *x++ = '\\';
  2273. X            *x++ = 'n';
  2274. X            continue;
  2275. X        case '\r':
  2276. X            *x++ = '\\';
  2277. X            *x++ = 'r';
  2278. X            continue;
  2279. X        case '\t':        /* horizontal tab */
  2280. X            *x++ = '\\';
  2281. X            *x++ = 't';
  2282. X            continue;
  2283. X        case '\\':        /* backslash */
  2284. X            *x++ = '\\';
  2285. X            *x++ = '\\';
  2286. X            continue;
  2287. X        case '"':        /* double quote */
  2288. X            *x++ = '\\';
  2289. X            *x++ = '"';
  2290. X            continue;
  2291. X        case '^':
  2292. X            *x++ = '\\';
  2293. X            *x++ = '^';
  2294. X            continue;
  2295. X        default:
  2296. X            if (isascii(*from))
  2297. X                if (iscntrl(*from)) {
  2298. X                    sprintf(x, "^%c", *from == '\177' ? '?' : *from + '@');
  2299. X                    x += 2;
  2300. X                } else
  2301. X                    *x++ = *from;
  2302. X            else {
  2303. X                sprintf(x, "\\%03o", *from);
  2304. X                x += 4;
  2305. X            }
  2306. X            continue;
  2307. X        }
  2308. X    *x = '\0';
  2309. X    return(x - to);
  2310. X}
  2311. X
  2312. Xstatic int unparse_character (from, to)
  2313. Xchar from;
  2314. Xchar *to;
  2315. X{
  2316. X    char *x = to;
  2317. X
  2318. X    switch (from) {
  2319. X    case '\b':        /* backspace */
  2320. X        *x++ = '\\';
  2321. X        *x++ = 'b';
  2322. X        break;
  2323. X    case '\f':        /* formfeed */
  2324. X        *x++ = '\\';
  2325. X        *x++ = 'f';
  2326. X        break;
  2327. X    case '\n':        /* newline */
  2328. X        *x++ = '\\';
  2329. X        *x++ = 'n';
  2330. X        break;
  2331. X    case '\r':
  2332. X        *x++ = '\\';
  2333. X        *x++ = 'r';
  2334. X        break;
  2335. X    case '\t':        /* horizontal tab */
  2336. X        *x++ = '\\';
  2337. X        *x++ = 't';
  2338. X        break;
  2339. X    case '\\':        /* backslash */
  2340. X        *x++ = '\\';
  2341. X        *x++ = '\\';
  2342. X        break;
  2343. X    case '\'':        /* single quote */
  2344. X        *x++ = '\\';
  2345. X        *x++ = '\'';
  2346. X        break;
  2347. X    case '^':
  2348. X        *x++ = '\\';
  2349. X        *x++ = '^';
  2350. X        break;
  2351. X    default:
  2352. X        if (isascii(from))
  2353. X            if (iscntrl(from)) {
  2354. X                sprintf(x, "^%c", from == '\177' ? '?' : from + '@');
  2355. X                x += 2;
  2356. X            } else
  2357. X                *x++ = from;
  2358. X        else {
  2359. X            sprintf(x, "\\%03o", from);
  2360. X            x += 4;
  2361. X        }
  2362. X        break;
  2363. X    }
  2364. X    *x = '\0';
  2365. X    return(x - to);
  2366. X}
  2367. X
  2368. X/*
  2369. X * write out a linked list of stanzas
  2370. X */
  2371. Xprofile_write_profile(f, s)
  2372. XFILE *f;
  2373. XPROFILE_STANZA *s;
  2374. X{
  2375. X    PROFILE_STANZA *x;
  2376. X
  2377. X    for (x = s; x != NULL; x = x->next) {
  2378. X        profile_write_stanza(f, x);
  2379. X        if (x->next == s)
  2380. X            break;
  2381. X    }
  2382. X}
  2383. !FaR!OuT!
  2384. if [ ! -d libtrw ]
  2385. then
  2386.     mkdir libtrw
  2387.     echo mkdir libtrw
  2388. fi
  2389. echo x - libtrw/Makefile
  2390. sed -e 's/^X//' > libtrw/Makefile << '!FaR!OuT!'
  2391. X# @(#)Makefile    1.1 (TRW) 1/14/86
  2392. XCFLAGS=    -O
  2393. XDEST= /usr/local/lib
  2394. XINCLUDE=/usr/include/local
  2395. X
  2396. X.c.o:
  2397. X    ${CC} ${CFLAGS} -c $*.c
  2398. X    -ld -x -r $*.o
  2399. X    mv a.out $*.o
  2400. X
  2401. Xall: libtrw.a
  2402. X
  2403. Xlibtrw.a: shift.o getopt.o getunent.o
  2404. X    ar cr libtrw.a shift.o getopt.o getunent.o
  2405. X    ranlib libtrw.a
  2406. X
  2407. Xclean:
  2408. X    rm -f *.o
  2409. X
  2410. Xinstall: all
  2411. X    mv libtrw.a $(DEST)
  2412. X    ranlib $(DEST)/libtrw.a
  2413. X    cp universe.h $(INCLUDE)
  2414. !FaR!OuT!
  2415. if [ ! -d libtrw ]
  2416. then
  2417.     mkdir libtrw
  2418.     echo mkdir libtrw
  2419. fi
  2420. echo x - libtrw/getopt.3
  2421. sed -e 's/^X//' > libtrw/getopt.3 << '!FaR!OuT!'
  2422. X.\" @(#)getopt.3    1.1 (TRW) 2/27/84
  2423. X.TH GETOPT 3C
  2424. X.SH NAME
  2425. Xgetopt \- get option letter from argument vector
  2426. X.SH SYNOPSIS
  2427. X.B int getopt (argc, argv, optstring)
  2428. X.br
  2429. X.B int argc;
  2430. X.br
  2431. X.B char \(**\(**argv;
  2432. X.br
  2433. X.B char \(**optstring;
  2434. X.PP
  2435. X.B extern char \(**optarg;
  2436. X.br
  2437. X.B extern int optind;
  2438. X.PP
  2439. Xcc ... -ltrw
  2440. X.SH DESCRIPTION
  2441. X.I Getopt\^
  2442. Xreturns the next option letter in
  2443. X.I argv\^
  2444. Xthat matches
  2445. Xa letter in
  2446. X.IR optstring .
  2447. X.I Optstring\^
  2448. Xis a string of recognized option letters;
  2449. Xif a letter is followed by a colon, the option
  2450. Xis expected to have an argument that may or
  2451. Xmay not be separated from it by white space.
  2452. X.I Optarg\^
  2453. Xis set to point to the start of the option argument
  2454. Xon return from
  2455. X.IR getopt .
  2456. X.PP
  2457. X.I Getopt\^
  2458. Xplaces in
  2459. X.I optind\^
  2460. Xthe
  2461. X.I argv\^
  2462. Xindex of the next argument to be processed.
  2463. XBecause
  2464. X.I optind\^
  2465. Xis external, it is normally initialized to zero
  2466. Xautomatically before the first call to
  2467. X.IR getopt .
  2468. X.PP
  2469. XWhen all options have been processed
  2470. X(i.e., up to the first non-option argument),
  2471. X.I getopt\^
  2472. Xreturns
  2473. X.SM
  2474. X.BR EOF .
  2475. XThe special option
  2476. X.B \-\-
  2477. Xmay be used to delimit the end of the options;
  2478. X.SM
  2479. X.B EOF
  2480. Xwill be returned, and
  2481. X.B \-\-
  2482. Xwill be skipped.
  2483. X.SH DIAGNOSTICS
  2484. X.I Getopt\^
  2485. Xprints an error message on
  2486. X.I stderr\^
  2487. Xand returns a
  2488. Xquestion mark
  2489. X.RB ( ? )
  2490. Xwhen it encounters an option letter not included in
  2491. X.IR optstring .
  2492. X.SH WARNING
  2493. XThe above routine uses \fB<stdio.h>\fP, which causes 
  2494. Xit to increase the size of programs,
  2495. Xnot otherwise using standard I/O, more
  2496. Xthan might be expected.
  2497. X.SH EXAMPLE
  2498. XThe following code fragment shows how one might process the arguments
  2499. Xfor a command that can take the mutually exclusive options
  2500. X.B a
  2501. Xand
  2502. X.BR b ,
  2503. Xand the options
  2504. X.B f
  2505. Xand
  2506. X.BR o ,
  2507. Xboth of which require arguments:
  2508. X.PP
  2509. X.RS
  2510. X.nf
  2511. X.ss 18
  2512. Xmain (argc, argv)
  2513. Xint argc;
  2514. Xchar \(**\(**argv;
  2515. X{
  2516. X    int c;
  2517. X    extern int optind;
  2518. X    extern char \(**optarg;
  2519. X    \&\f3.\fP
  2520. X    \&\f3.\fP
  2521. X    \&\f3.\fP
  2522. X    while ((c = getopt (argc, argv, "abf:o:")) != \s-1EOF\s+1)
  2523. X        switch (c) {
  2524. X        case \(fma\(fm:
  2525. X            if (bflg)
  2526. X                errflg++;
  2527. X            else
  2528. X                aflg++;
  2529. X            break;
  2530. X        case \(fmb\(fm:
  2531. X            if (aflg)
  2532. X                errflg++;
  2533. X            else
  2534. X                bproc( );
  2535. X            break;
  2536. X        case \(fmf\(fm:
  2537. X            ifile = optarg;
  2538. X            break;
  2539. X        case \(fmo\(fm:
  2540. X            ofile = optarg;
  2541. X            bufsiza = 512;
  2542. X            break;
  2543. X        case \(fm?\(fm:
  2544. X            errflg++;
  2545. X        }
  2546. X    if (errflg) {
  2547. X        fprintf (stderr, "usage: . . . ");
  2548. X        exit (2);
  2549. X    }
  2550. X    for ( ; optind < argc; optind++) {
  2551. X        if (access (argv[optind], 4)) {
  2552. X    \&\f3.\fP
  2553. X    \&\f3.\fP
  2554. X    \&\f3.\fP
  2555. X}
  2556. X.ss 12
  2557. X.fi
  2558. X.RE
  2559. X.\"    @(#)getopt.3c    5.2 of 5/18/82
  2560. !FaR!OuT!
  2561. if [ ! -d libtrw ]
  2562. then
  2563.     mkdir libtrw
  2564.     echo mkdir libtrw
  2565. fi
  2566. echo x - libtrw/getopt.c
  2567. sed -e 's/^X//' > libtrw/getopt.c << '!FaR!OuT!'
  2568. Xstatic char *trwsccs = "@(#)getopt.c    1.1 (TRW) 1/14/86";
  2569. X/* This is the System V getopt(3), modified to use index(3) instead
  2570. X * of strchr(3).
  2571. X */
  2572. X
  2573. X/*    @(#)getopt.c    1.2    */
  2574. X/*    3.0 SID #    1.2    */
  2575. X/*LINTLIBRARY*/
  2576. X#include <stdio.h>
  2577. X#define ERR(s, c)    if(opterr){\
  2578. X    (void) fputs(argv[0], stderr);\
  2579. X    (void) fputs(s, stderr);\
  2580. X    (void) fputc(c, stderr);\
  2581. X    (void) fputc('\n', stderr);}
  2582. X
  2583. Xextern int strcmp();
  2584. Xextern char *index();
  2585. X
  2586. Xint    opterr = 1;
  2587. Xint    optind = 1;
  2588. Xint    optopt;
  2589. Xchar    *optarg;
  2590. X
  2591. Xint
  2592. Xgetopt(argc, argv, opts)
  2593. Xint    argc;
  2594. Xchar    **argv, *opts;
  2595. X{
  2596. X    static int sp = 1;
  2597. X    register int c;
  2598. X    register char *cp;
  2599. X
  2600. X    if(sp == 1)
  2601. X        if(optind >= argc ||
  2602. X           argv[optind][0] != '-' || argv[optind][1] == '\0')
  2603. X            return(EOF);
  2604. X        else if(strcmp(argv[optind], "--") == NULL) {
  2605. X            optind++;
  2606. X            return(EOF);
  2607. X        }
  2608. X    optopt = c = argv[optind][sp];
  2609. X    if(c == ':' || (cp=index(opts, c)) == NULL) {
  2610. X        ERR(": illegal option -- ", c);
  2611. X        if(argv[optind][++sp] == '\0') {
  2612. X            optind++;
  2613. X            sp = 1;
  2614. X        }
  2615. X        return('?');
  2616. X    }
  2617. X    if(*++cp == ':') {
  2618. X        if(argv[optind][sp+1] != '\0')
  2619. X            optarg = &argv[optind++][sp+1];
  2620. X        else if(++optind >= argc) {
  2621. X            ERR(": option requires an argument -- ", c);
  2622. X            sp = 1;
  2623. X            return('?');
  2624. X        } else
  2625. X            optarg = argv[optind++];
  2626. X        sp = 1;
  2627. X    } else {
  2628. X        if(argv[optind][++sp] == '\0') {
  2629. X            sp = 1;
  2630. X            optind++;
  2631. X        }
  2632. X        optarg = NULL;
  2633. X    }
  2634. X    return(c);
  2635. X}
  2636. !FaR!OuT!
  2637. if [ ! -d libtrw ]
  2638. then
  2639.     mkdir libtrw
  2640.     echo mkdir libtrw
  2641. fi
  2642. echo x - libtrw/getunent.3
  2643. sed -e 's/^X//' > libtrw/getunent.3 << '!FaR!OuT!'
  2644. X.TH GETUNENT 3-ucb
  2645. X.SH NAME
  2646. Xgetunent, getunnam, setunent, endunent \- get universe file entry
  2647. X.SH ORIGIN
  2648. X4.2BSD
  2649. X.SH SYNOPSIS
  2650. X.nf
  2651. X.B #include <local/universe.h>
  2652. X.PP
  2653. X.B struct universe *getunent()
  2654. X.PP
  2655. X.B struct universe *getunnam(name)
  2656. X.B char *name;
  2657. X.PP
  2658. X.B int setunent()
  2659. X.PP
  2660. X.B int endunent()
  2661. X.PP
  2662. Xcc ... -ltrw
  2663. X.fi
  2664. X.SH DESCRIPTION
  2665. X.I Getunent
  2666. Xand
  2667. X.I getunnam
  2668. Xeach return a pointer to an object with the
  2669. Xfollowing structure,
  2670. Xcontaining the broken-out
  2671. Xfields of a line in the universe file.
  2672. X.RS
  2673. X.PP
  2674. X.nf
  2675. X.so /usr/include/local/universe.h
  2676. X.ft R
  2677. X.ad
  2678. X.fi
  2679. X.RE
  2680. X.PP
  2681. X.I Getunent
  2682. Xreads the next
  2683. Xline (opening the file if necessary);
  2684. X.I setunent
  2685. Xrewinds the file;
  2686. X.I endunent
  2687. Xcloses it.
  2688. X.PP
  2689. X.I Getunnam
  2690. Xsearches from the beginning until a matching
  2691. X.I name
  2692. Xis found
  2693. X(or until EOF is encountered).
  2694. X.SH FILES
  2695. X/etc/u_universe
  2696. X.SH AUTHOR
  2697. XScott Simpson, TRW
  2698. X.SH "SEE ALSO"
  2699. Xu_universe(5)
  2700. X.SH DIAGNOSTICS
  2701. XNull pointer
  2702. X(0) returned on EOF or error.
  2703. X.SH BUGS
  2704. XAll information
  2705. Xis contained in a static area,
  2706. Xso it must be copied if it is
  2707. Xto be saved.
  2708. !FaR!OuT!
  2709. if [ ! -d libtrw ]
  2710. then
  2711.     mkdir libtrw
  2712.     echo mkdir libtrw
  2713. fi
  2714. echo x - libtrw/getunent.c
  2715. sed -e 's/^X//' > libtrw/getunent.c << '!FaR!OuT!'
  2716. X/* Scott Simpson, TRW */
  2717. X#include <stdio.h>
  2718. X#include <local/universe.h>
  2719. X
  2720. Xstatic char UNIVERSE[]    = "/etc/u_universe";
  2721. Xstatic char EMPTY[] = "";
  2722. Xstatic FILE *uf = NULL;
  2723. Xstatic char line[BUFSIZ+1];
  2724. Xstatic char name[80];
  2725. Xstatic char univ[80];
  2726. Xstatic struct universe universe;
  2727. X
  2728. Xsetunent()
  2729. X{
  2730. X    if( uf == NULL )
  2731. X        uf = fopen(UNIVERSE, "r" );
  2732. X    else
  2733. X        rewind( uf );
  2734. X}
  2735. X
  2736. Xendunent()
  2737. X{
  2738. X    if( uf != NULL ){
  2739. X        fclose( uf );
  2740. X        uf = NULL;
  2741. X    }
  2742. X}
  2743. X
  2744. Xstruct universe *
  2745. Xgetunent()
  2746. X{
  2747. X    register char *p;
  2748. X    if (uf == NULL) {
  2749. X        if( (uf = fopen( UNIVERSE, "r" )) == NULL )
  2750. X            return(0);
  2751. X    }
  2752. X    while (1) {
  2753. X        p = fgets(line, BUFSIZ, uf);
  2754. X        if (p==NULL)
  2755. X            return(0);
  2756. X        if (line[strlen(line)-1]=='\n')line[strlen(line)-1]='\0';
  2757. X        if (strlen(line) == 0 || line[0] == '#' || line[0] == ':')
  2758. X            continue;
  2759. X        if (sscanf(line, "%[^:]:%s", name, univ) != 2) {
  2760. X            return(0);
  2761. X}        else {
  2762. X            universe.un_name = &name[0];
  2763. X            universe.un_universe = &univ[0];
  2764. X            break;
  2765. X        }
  2766. X    }
  2767. X    return(&universe);
  2768. X}
  2769. X
  2770. Xgetunnam(name)
  2771. Xchar *name;
  2772. X{
  2773. X    register struct universe *u;
  2774. X
  2775. X    setunent();
  2776. X    while ( (u = getunent()) && strcmp(name,u->un_name) );
  2777. X    endpwent();
  2778. X    return(u);
  2779. X}
  2780. !FaR!OuT!
  2781. if [ ! -d libtrw ]
  2782. then
  2783.     mkdir libtrw
  2784.     echo mkdir libtrw
  2785. fi
  2786. echo x - libtrw/shift.3
  2787. sed -e 's/^X//' > libtrw/shift.3 << '!FaR!OuT!'
  2788. X.\" @(#)shift.3    1.1 (TRW) 11/15/83
  2789. X.TH SHIFT 3 TRW
  2790. X.UC
  2791. X.SH NAME
  2792. Xstring_downshift, string_upshift \- shift case of strings
  2793. X.SH SYNOPSIS
  2794. X.nf
  2795. X.B char *string_downshift(s)
  2796. X.B char *s;
  2797. X
  2798. X.B char *string_upshift(s)
  2799. X.B char *s;
  2800. X
  2801. X.B cc ... -ltrw
  2802. X.fi
  2803. X.SH DESCRIPTION
  2804. X.I String_downshift 
  2805. Xshifts 
  2806. X.I s 
  2807. Xin place to lowercase.
  2808. X.I String_upshift 
  2809. Xshifts
  2810. X.I s
  2811. Xin place to uppercase.
  2812. XBoth routines return
  2813. X.I s.
  2814. X.SH AUTHOR
  2815. XMichael Gorlick, TRW
  2816. X.SH SEE ALSO
  2817. Xctype(3), string(3)
  2818. !FaR!OuT!
  2819. if [ ! -d libtrw ]
  2820. then
  2821.     mkdir libtrw
  2822.     echo mkdir libtrw
  2823. fi
  2824. echo x - libtrw/shift.c
  2825. sed -e 's/^X//' > libtrw/shift.c << '!FaR!OuT!'
  2826. Xstatic char *trwsccs = "@(#)shift.c    1.1 (TRW) 1/14/86";
  2827. X#include <ctype.h>
  2828. X
  2829. X/*
  2830. X * Downshifts a string in place.
  2831. X */
  2832. Xchar *string_downshift(s)
  2833. Xchar *s;
  2834. X{
  2835. X
  2836. X    register char *x = s;
  2837. X    for (; *x; x++)
  2838. X        if (isupper(*x))
  2839. X            *x = tolower(*x);
  2840. X    return(s);
  2841. X}
  2842. X
  2843. X/*
  2844. X * Upshifts a string in place.
  2845. X */
  2846. Xchar *string_upshift(s)
  2847. Xchar *s;
  2848. X{
  2849. X
  2850. X    register char *x = s;
  2851. X    for (; *x; x++)
  2852. X        if (islower(*x))
  2853. X            *x = toupper(*x);
  2854. X    return(s);
  2855. X}
  2856. !FaR!OuT!
  2857. if [ ! -d libtrw ]
  2858. then
  2859.     mkdir libtrw
  2860.     echo mkdir libtrw
  2861. fi
  2862. echo x - libtrw/universe.h
  2863. sed -e 's/^X//' > libtrw/universe.h << '!FaR!OuT!'
  2864. Xstruct    universe { /* see getunent(3) */
  2865. X    char    *un_name;
  2866. X    char    *un_universe;
  2867. X};
  2868. X
  2869. Xstruct universe *getunent(), *getunnam();
  2870. !FaR!OuT!
  2871. exit
  2872. -- 
  2873.         Scott Simpson
  2874.         TRW Electronics and Defense Sector
  2875.         ...{decvax,ihnp4,ucbvax}!trwrb!simpson
  2876.  
  2877.  
  2878.