home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume34 / imagemagick / part03 < prev    next >
Text File  |  1992-12-14  |  58KB  |  1,902 lines

  1. Newsgroups: comp.sources.misc
  2. From: cristy@eplrx7.es.duPont.com (John Cristy)
  3. Subject:  v34i031:  imagemagick - X11 image processing and display v2.2, Part03/26
  4. Message-ID: <1992Dec13.202349.7975@sparky.imd.sterling.com>
  5. X-Md4-Signature: dcedf45d348e8c1204f2200228373068
  6. Date: Sun, 13 Dec 1992 20:23:49 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: cristy@eplrx7.es.duPont.com (John Cristy)
  10. Posting-number: Volume 34, Issue 31
  11. Archive-name: imagemagick/part03
  12. Environment: UNIX, VMS, X11, SGI, DEC, Cray, Sun, Vax
  13.  
  14. #!/bin/sh
  15. # this is Part.03 (part 3 of a multipart archive)
  16. # do not concatenate these parts, unpack them in order with /bin/sh
  17. # file ImageMagick/xtp/regular.c continued
  18. #
  19. if test ! -r _shar_seq_.tmp; then
  20.     echo 'Please unpack part 1 first!'
  21.     exit 1
  22. fi
  23. (read Scheck
  24.  if test "$Scheck" != 3; then
  25.     echo Please unpack part "$Scheck" next!
  26.     exit 1
  27.  else
  28.     exit 0
  29.  fi
  30. ) < _shar_seq_.tmp || exit 1
  31. if test ! -f _shar_wnt_.tmp; then
  32.     echo 'x - still skipping ImageMagick/xtp/regular.c'
  33. else
  34. echo 'x - continuing file ImageMagick/xtp/regular.c'
  35. sed 's/^X//' << 'SHAR_EOF' >> 'ImageMagick/xtp/regular.c' &&
  36. %  & Company not be used in advertising or publicity pertaining to            %
  37. %  distribution of the software without specific, written prior               %
  38. %  permission.  E. I. Dupont de Nemours & Company makes no representations    %
  39. %  about the suitability of this software for any purpose.  It is provided    %
  40. %  "as is" without express or implied warranty.                               %
  41. %                                                                             %
  42. %  E. I. Dupont de Nemours & Company disclaims all warranties with regard     %
  43. %  to this software, including all implied warranties of merchantability      %
  44. %  and fitness, in no event shall E. I. Dupont de Nemours & Company be        %
  45. %  liable for any special, indirect or consequential damages or any           %
  46. %  damages whatsoever resulting from loss of use, data or profits, whether    %
  47. %  in an action of contract, negligence or other tortious action, arising     %
  48. %  out of or in connection with the use or performance of this software.      %
  49. %                                                                             %
  50. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  51. %
  52. %  CompileRegularExpression returns NULL for a failure, where failures are
  53. %  syntax errors, exceeding implementation limits, or applying `+' or `*'
  54. %  to a possibly-null operand.
  55. %
  56. %  This is essentially the same routine written and copywrited by Henry
  57. %  Spencer, University of Toronto.  I made minor programming changes but
  58. %  major variable name changes to improve readability.
  59. %
  60. %  A regular expression is zero or more branches, separated by `|'. It
  61. %  matches anything that matches one of the branches.
  62. %
  63. %  A branch is zero or more pieces, concatenated. It matches a match for
  64. %  the first, followed by a match for the second, etc.
  65. %
  66. %  A piece is an atom possibly followed by `*', `+', or `?'. An atom
  67. %  followed by `*' matches a sequence of 0 or more matches of the atom. An
  68. %  atom followed by `+' matches a sequence of 1 or more matches of the
  69. %  atom. An atom followed by `?' matches a match of the atom, or the null
  70. %  pattern.
  71. %
  72. %  An atom is a regular expression in parentheses (matching a match for
  73. %  the regular expression), a range (see below), `.' (matching any single
  74. %  character), `^' (matching the null pattern at the beginning of the input
  75. %  pattern), `$' (matching the null pattern at the end of the input pattern),
  76. %  a `\' followed by a single character (matching that character), or a
  77. %  single character with no other significance (matching that character).
  78. %
  79. %  A range is a sequence of characters enclosed in `[]'. It normally
  80. %  matches any single character from the sequence. If the sequence begins
  81. %  with `^', it matches any single character not from the rest of the
  82. %  sequence. If two characters in the sequence are separated by `-', this
  83. %  is shorthand for the full list of ASCII characters between them (e.g.
  84. %  `[0-9]' matches any decimal digit). To include a literal `]' in the
  85. %  sequence, make it the first character (following a possible `^').  To
  86. %  include a literal `-', make it the first or last character.
  87. %
  88. %  If a regular expression could match two different parts of the input
  89. %  pattern, it will match the one which begins earliest. If both begin in
  90. %  the same place but match different lengths, or match the same length
  91. %  in different ways, life gets messier, as follows.
  92. %
  93. %  In general, the possibilities in a list of branches are considered in
  94. %  left-to-right order, the possibilities for `*', `+', and `?' are
  95. %  considered longest-first, nested constructs are considered from the
  96. %  outermost in, and concatenated constructs are considered
  97. %  leftmost-first. The match that will be chosen is the one that uses the
  98. %  earliest possibility in the first choice that has to be made. If there
  99. %  is more than one choice, the next will be made in the same manner
  100. %  (earliest possibility) subject to the decision on the first choice.
  101. %  And so forth.
  102. %
  103. %  For example, `(ab|a)b*c' could match `abc' in one of two ways. The
  104. %  first choice is between `ab' and `a'; since `ab' is earlier, and does
  105. %  lead to a successful overall match, it is chosen. Since the `b' is
  106. %  already spoken for, the `b*' must match its last possibility-the empty
  107. %  pattern-since it must respect the earlier choice.
  108. %
  109. %  In the particular case where no `|'s are present and there is only one
  110. %  `*', `+', or `?', the net effect is that the longest possible match
  111. %  will be chosen. So `ab*', presented with `xabbbby', will match `abbbb'.
  112. %  Note that if `ab*' is tried against `xabyabbbz', it will match `ab'
  113. %  just after `x', due to the begins-earliest rule. (In effect, the deci-
  114. %  sion on where to start the match is the first choice to be made, hence
  115. %  subsequent choices must respect it even if this leads them to
  116. %  less-preferred alternatives.)
  117. %
  118. %
  119. */
  120. X
  121. #include "xtp.h"
  122. #include "regular.h"
  123. X
  124. /*
  125. X  Variable declarations.
  126. */
  127. char
  128. X  *code,
  129. X  **subpattern_end,
  130. X  *p,
  131. X  start_code,
  132. X  *start_pattern,
  133. X  **subpattern;
  134. X
  135. static char
  136. X  *token;
  137. X
  138. static int
  139. X  number_parenthesis;
  140. X
  141. static long
  142. X  code_size;
  143. X
  144. /*
  145. X  Forward declarations.
  146. */
  147. static char
  148. X  *NextToken _Declare((register char *)),
  149. X  *Node _Declare((int)),
  150. X  *Piece _Declare((int *)),
  151. X  *Regular _Declare((int,int *));
  152. X
  153. static int
  154. X  Repeat _Declare((char *));
  155. X
  156. static void
  157. X  EmitCode _Declare((int)),
  158. X  Tail _Declare((char *,char *));
  159. X
  160. /*
  161. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  162. %                                                                             %
  163. %                                                                             %
  164. %                                                                             %
  165. %   A t o m                                                                   %
  166. %                                                                             %
  167. %                                                                             %
  168. %                                                                             %
  169. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  170. %
  171. %
  172. */
  173. static char *Atom(flagp)
  174. int
  175. X  *flagp;
  176. {
  177. X  int
  178. X    flags;
  179. X
  180. X  register char
  181. X    *status;
  182. X
  183. X  *flagp=WorstCase;
  184. X  switch(*token++)
  185. X  {
  186. X    case '^':
  187. X    {
  188. X      status=Node(MatchBeginningOfLine);
  189. X      break;
  190. X    }
  191. X    case '$':
  192. X    {
  193. X      status=Node(MatchEndOfProgramOfLine);
  194. X      break;
  195. X    }
  196. X    case '.':
  197. X    {
  198. X      status=Node(MatchAnyCharacter);
  199. X      *flagp|=NonNull | Simple;
  200. X      break;
  201. X    }
  202. X    case '[':
  203. X    {
  204. X      register int
  205. X        class,
  206. X        class_end;
  207. X
  208. X      if (*token != '^')
  209. X        status=Node(MatchAnyCharacterOf);
  210. X      else
  211. X        {
  212. X          /*
  213. X            Complement of range.
  214. X          */
  215. X          status=Node(MatchAnyCharacterBut);
  216. X          token++;
  217. X        }
  218. X      if ((*token == ']') || (*token == '-'))
  219. X        EmitCode(*token++);
  220. X      while ((*token != '\0') && (*token != ']'))
  221. X      {
  222. X        if (*token != '-')
  223. X          EmitCode(*token++);
  224. X         else
  225. X          {
  226. X            token++;
  227. X            if ((*token == ']') || (*token == '\0'))
  228. X              EmitCode('-');
  229. X            else
  230. X              {
  231. X                class=((int)*(unsigned char *)(token-2))+1;
  232. X                class_end=((int)*(unsigned char *)(token));
  233. X                if (class > class_end+1)
  234. X                  Fail("invalid [] range");
  235. X                for(; class <= class_end; class++)
  236. X                  EmitCode((char) class);
  237. X                token++;
  238. X              }
  239. X          }
  240. X      }
  241. X      EmitCode('\0');
  242. X      if (*token != ']')
  243. X        Fail("unmatched []");
  244. X      token++;
  245. X      *flagp|=NonNull | Simple;
  246. X      break;
  247. X    }
  248. X    case '(':
  249. X    {
  250. X      status=Regular(1,&flags);
  251. X      if (status == NULL)
  252. X        return(NULL);
  253. X      *flagp|=flags & (NonNull | SpecialStart);
  254. X      break;
  255. X    }
  256. X    case '\0':
  257. X    case '|':
  258. X    case ')':
  259. X    {
  260. X      Fail("internal urp");
  261. X      break;
  262. X    }
  263. X    case '?':
  264. X    case '+':
  265. X    case '*':
  266. X    {
  267. X      Fail("?+* follows nothing");
  268. X      break;
  269. X    }
  270. X    case '\\':
  271. X    {
  272. X      if (*token == '\0')
  273. X        Fail("trailing \\");
  274. X      status=Node(MatchExactly);
  275. X      EmitCode(*token++);
  276. X      EmitCode('\0');
  277. X      *flagp|=NonNull | Simple;
  278. X      break;
  279. X    }
  280. X    default:
  281. X    {
  282. X      register char
  283. X        ender;
  284. X
  285. X      register int
  286. X        length;
  287. X
  288. X      token--;
  289. X      length=strcspn(token,Meta);
  290. X      if (length <= 0)
  291. X        Fail("internal disaster");
  292. X      ender=(*(token+length));
  293. X      if (length > 1 && MultipleMatches(ender))
  294. X        length--;
  295. X      *flagp|=NonNull;
  296. X      if (length == 1)
  297. X        *flagp|=Simple;
  298. X      status=Node(MatchExactly);
  299. X      while (length > 0)
  300. X      {
  301. X        EmitCode(*token++);
  302. X        length--;
  303. X      }
  304. X      EmitCode('\0');
  305. X      break;
  306. X    }
  307. X  }
  308. X  return(status);
  309. }
  310. X
  311. /*
  312. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  313. %                                                                             %
  314. %                                                                             %
  315. %                                                                             %
  316. %   B r a n c h                                                               %
  317. %                                                                             %
  318. %                                                                             %
  319. %                                                                             %
  320. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  321. %
  322. %  Function Branch Implements the | operator.
  323. %
  324. %
  325. */
  326. static char *Branch(flagp)
  327. int
  328. X  *flagp;
  329. {
  330. X  int
  331. X    flags;
  332. X
  333. X  register char
  334. X    *chain,
  335. X    *latest,
  336. X    *status;
  337. X
  338. X  *flagp=WorstCase;
  339. X  status=Node(MatchThisOrNext);
  340. X  chain=NULL;
  341. X  while ((*token != '\0') && (*token != '|') && (*token != ')'))
  342. X  {
  343. X    latest=Piece(&flags);
  344. X    if (latest == NULL)
  345. X      return(NULL);
  346. X    *flagp|=flags & NonNull;
  347. X    if (chain == NULL)
  348. X      *flagp|=flags & SpecialStart;
  349. X    else
  350. X      Tail(chain,latest);
  351. X    chain=latest;
  352. X  }
  353. X  if (chain == NULL)
  354. X   (void) Node(MatchEmptyString);
  355. X  return(status);
  356. }
  357. X
  358. /*
  359. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  360. %                                                                             %
  361. %                                                                             %
  362. %                                                                             %
  363. %   E m i t C o d e                                                           %
  364. %                                                                             %
  365. %                                                                             %
  366. %                                                                             %
  367. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  368. %
  369. %
  370. */
  371. static void EmitCode(opcode)
  372. int
  373. X  opcode;
  374. {
  375. X  if (code != &start_code)
  376. X    *code++=(char) opcode;
  377. X  else
  378. X    code_size++;
  379. }
  380. X
  381. /*
  382. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  383. %                                                                             %
  384. %                                                                             %
  385. %                                                                             %
  386. %   I n s e r t                                                               %
  387. %                                                                             %
  388. %                                                                             %
  389. %                                                                             %
  390. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  391. %
  392. %  Function Insert inserts an operator in front of an already-emitted operand.
  393. %
  394. */
  395. static void Insert(opcode,operand)
  396. char
  397. X  opcode,
  398. X  *operand;
  399. {
  400. X  register char
  401. X    *p,
  402. X    *place,
  403. X    *q;
  404. X
  405. X  if (code == &start_code)
  406. X    {
  407. X      code_size+=3;
  408. X      return;
  409. X    }
  410. X  p=code;
  411. X  code+=3;
  412. X  q=code;
  413. X  while (p > operand)
  414. X    *--q=(*--p);
  415. X  place=operand;
  416. X  *place++=opcode;
  417. X  *place++='\0';
  418. X  *place++='\0';
  419. }
  420. X
  421. /*
  422. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  423. %                                                                             %
  424. %                                                                             %
  425. %                                                                             %
  426. %   M a t c h                                                                 %
  427. %                                                                             %
  428. %                                                                             %
  429. %                                                                             %
  430. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  431. %
  432. %
  433. */
  434. static int Match(regular_expression)
  435. char
  436. X  *regular_expression;
  437. {
  438. X  char
  439. X    *next_token;
  440. X
  441. X  register char
  442. X    *scan;
  443. X
  444. X  scan=regular_expression;
  445. X  while (scan != NULL)
  446. X  {
  447. X    next_token=NextToken(scan);
  448. X    switch(OpCode(scan))
  449. X    {
  450. X      case MatchBeginningOfLine:
  451. X      {
  452. X        if (p != start_pattern)
  453. X          return(0);
  454. X        break;
  455. X      }
  456. X      case MatchEndOfProgramOfLine:
  457. X      {
  458. X        if (*p != '\0')
  459. X         return(0);
  460. X        break;
  461. X      }
  462. X      case MatchAnyCharacter:
  463. X      {
  464. X        if (*p == '\0')
  465. X          return(0);
  466. X        p++;
  467. X        break;
  468. X      }
  469. X      case MatchExactly:
  470. X      {
  471. X        register char
  472. X          *operand;
  473. X
  474. X        register int
  475. X          length;
  476. X
  477. X        operand=Operand(scan);
  478. X        /*
  479. X          Inline the first character for speed.
  480. X        */
  481. X        if (*operand != *p)
  482. X          return(0);
  483. X        length=strlen(operand);
  484. X        if ((length > 1) && (strncmp(operand,p,length) != 0))
  485. X          return(0);
  486. X        p+=length;
  487. X        break;
  488. X      }
  489. X      case MatchAnyCharacterOf:
  490. X      {
  491. X        if ((*p == '\0' || strchr(Operand(scan),*p) == NULL))
  492. X          return(0);
  493. X        p++;
  494. X        break;
  495. X      }
  496. X      case MatchAnyCharacterBut:
  497. X      {
  498. X        if ((*p == '\0') || (strchr(Operand(scan),*p) != NULL))
  499. X          return(0);
  500. X        p++;
  501. X        break;
  502. X      }
  503. X      case MatchEmptyString:
  504. X        break;
  505. X      case Back:
  506. X        break;
  507. X      case Open+1:
  508. X      case Open+2:
  509. X      case Open+3:
  510. X      case Open+4:
  511. X      case Open+5:
  512. X      case Open+6:
  513. X      case Open+7:
  514. X      case Open+8:
  515. X      case Open+9:
  516. X      {
  517. X        register char
  518. X          *save;
  519. X
  520. X        register int
  521. X          no;
  522. X
  523. X        no=OpCode(scan)-Open;
  524. X        save=p;
  525. X        if (!Match(next_token))
  526. X          return(0);
  527. X        else
  528. X          {
  529. X            /*
  530. X              Don't set subpattern if some later invocation of the same
  531. X              parentheses already has.
  532. X            */
  533. X            if (subpattern[no] == NULL)
  534. X              subpattern[no]=save;
  535. X            return(1);
  536. X          }
  537. X        break;
  538. X      }
  539. X      case Close+1:
  540. X      case Close+2:
  541. X      case Close+3:
  542. X      case Close+4:
  543. X      case Close+5:
  544. X      case Close+6:
  545. X      case Close+7:
  546. X      case Close+8:
  547. X      case Close+9:
  548. X      {
  549. X        register char
  550. X          *save;
  551. X
  552. X        register int
  553. X          no;
  554. X
  555. X        no=OpCode(scan)-Close;
  556. X        save=p;
  557. X        if (!Match(next_token))
  558. X           return(0);
  559. X        else
  560. X          {
  561. X            /*
  562. X              Don't set subpattern_end if some later invocation of the same
  563. X              parentheses already has.
  564. X            */
  565. X            if (subpattern_end[no] == NULL)
  566. X              subpattern_end[no]=save;
  567. X            return(1);
  568. X          }
  569. X        break;
  570. X      }
  571. X      case MatchThisOrNext:
  572. X      {
  573. X        register char
  574. X          *save;
  575. X
  576. X        if (OpCode(next_token) != MatchThisOrNext)
  577. X          next_token=Operand(scan);
  578. X        else
  579. X          {
  580. X            do
  581. X            {
  582. X              save=p;
  583. X              if (Match(Operand(scan)))
  584. X                return(1);
  585. X              p=save;
  586. X              scan=NextToken(scan);
  587. X            } while ((scan != NULL) && (OpCode(scan) == MatchThisOrNext));
  588. X            return(0);
  589. X          }
  590. X        break;
  591. X      }
  592. X      case MatchZeroOrMore:
  593. X      case MatchOneOrMore:
  594. X      {
  595. X        register char
  596. X          next_tokench,
  597. X          *save;
  598. X
  599. X        register int
  600. X          min,
  601. X          no;
  602. X
  603. X        /*
  604. X          Lookahead to avoid useless match attempts when we know what
  605. X          character comes next_token.
  606. X        */
  607. X        next_tokench='\0';
  608. X        if (OpCode(next_token) == MatchExactly)
  609. X          next_tokench=(*Operand(next_token));
  610. X        min=(OpCode(scan) == MatchZeroOrMore) ? 0 : 1;
  611. X        save=p;
  612. X        no=Repeat(Operand(scan));
  613. X        while (no >= min)
  614. X        {
  615. X          /*
  616. X            If it could work, try it.
  617. X          */
  618. X          if ((next_tokench == '\0') || (*p == next_tokench))
  619. X            if (Match(next_token))
  620. X              return(1);
  621. X          /*
  622. X            Couldn't or didn't -- back up.
  623. X          */
  624. X          no--;
  625. X          p=save+no;
  626. X        }
  627. X        return(0);
  628. X        break;
  629. X      }
  630. X      case EndOfProgram:
  631. X        return(1);
  632. X        break;
  633. X      default:
  634. X        (void) fprintf(stderr,"Regular(3): %s","memory corruption");
  635. X        return(0);
  636. X        break;
  637. X    }
  638. X    scan=next_token;
  639. X  }
  640. X  (void) fprintf(stderr,"Regular(3): %s","corrupted pointers");
  641. X  return(0);
  642. }
  643. X
  644. /*
  645. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  646. %                                                                             %
  647. %                                                                             %
  648. %                                                                             %
  649. %   N e x t T o k e n                                                         %
  650. %                                                                             %
  651. %                                                                             %
  652. %                                                                             %
  653. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  654. %
  655. %
  656. */
  657. static char *NextToken(p)
  658. register char
  659. X  *p;
  660. {
  661. X  register int
  662. X    offset;
  663. X
  664. X  if (p == &start_code)
  665. X    return(NULL);
  666. X  offset=Next(p);
  667. X  if (offset == 0)
  668. X    return(NULL);
  669. X  if (OpCode(p) == Back)
  670. X    return(p-offset);
  671. X  else
  672. X    return(p+offset);
  673. }
  674. X
  675. /*
  676. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  677. %                                                                             %
  678. %                                                                             %
  679. %                                                                             %
  680. %   N o d e                                                                   %
  681. %                                                                             %
  682. %                                                                             %
  683. %                                                                             %
  684. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  685. %
  686. %
  687. */
  688. static char *Node(opcode)
  689. int
  690. X  opcode;
  691. {
  692. X  register char
  693. X    *ptr,
  694. X    *status;
  695. X
  696. X  status=code;
  697. X  if (status == &start_code)
  698. X    {
  699. X      code_size+=3;
  700. X      return(status);
  701. X    }
  702. X  ptr=status;
  703. X  *ptr++=(char) opcode;
  704. X  *ptr++='\0';
  705. X  *ptr++='\0';
  706. X  code=ptr;
  707. X  return(status);
  708. }
  709. X
  710. /*
  711. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  712. %                                                                             %
  713. %                                                                             %
  714. %                                                                             %
  715. %   O p T a i l                                                               %
  716. %                                                                             %
  717. %                                                                             %
  718. %                                                                             %
  719. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  720. %
  721. %
  722. */
  723. static void OpTail(p,value)
  724. char
  725. X  *p;
  726. X
  727. char
  728. X  *value;
  729. {
  730. X  /*
  731. X    "Operandless" and "op != MatchThisOrNext" are synonymous in practice.
  732. X  */
  733. X  if ((p == NULL) || (p == &start_code) || (OpCode(p) != MatchThisOrNext))
  734. X    return;
  735. X  Tail(Operand(p),value);
  736. }
  737. X
  738. /*
  739. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  740. %                                                                             %
  741. %                                                                             %
  742. %                                                                             %
  743. %   P i e c e                                                                 %
  744. %                                                                             %
  745. %                                                                             %
  746. %                                                                             %
  747. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  748. %
  749. %
  750. */
  751. static char *Piece(flagp)
  752. int
  753. X  *flagp;
  754. {
  755. X  int
  756. X    flags;
  757. X
  758. X  register char
  759. X    *next_token,
  760. X    op,
  761. X    *status;
  762. X
  763. X  status=Atom(&flags);
  764. X  if (status == NULL)
  765. X    return(NULL);
  766. X  op=(*token);
  767. X  if (!MultipleMatches(op))
  768. X    {
  769. X      *flagp=flags;
  770. X      return(status);
  771. X    }
  772. X  if (!(flags & NonNull) && op != '?')
  773. X    Fail("*+ operand could be empty");
  774. X  *flagp=(op != '+') ? (WorstCase | SpecialStart) : (WorstCase | NonNull);
  775. X  if (op == '*' && (flags & Simple))
  776. X    Insert(MatchZeroOrMore,status);
  777. X  else
  778. X    if (op == '*')
  779. X      {
  780. X        /*
  781. X          Emit x* as (x&|), where & means "self".
  782. X        */
  783. X        Insert(MatchThisOrNext,status);
  784. X        OpTail(status,Node(Back));
  785. X        OpTail(status,status);
  786. X        Tail(status,Node(MatchThisOrNext));
  787. X        Tail(status,Node(MatchEmptyString));
  788. X      }
  789. X    else
  790. X      if ((op == '+') && (flags & Simple))
  791. X        Insert(MatchOneOrMore,status);
  792. X      else
  793. X        if (op == '+')
  794. X          {
  795. X            /*
  796. X              Emit x+ as x (&|), where & means "self".
  797. X            */
  798. X            next_token=Node(MatchThisOrNext);
  799. X            Tail(status,next_token);
  800. X            Tail(Node(Back),status);
  801. X            Tail(next_token,Node(MatchThisOrNext));
  802. X            Tail(status,Node(MatchEmptyString));
  803. X          }
  804. X        else
  805. X          if (op == '?')
  806. X            {
  807. X              /*
  808. X                Emit x? as (x|)
  809. X              */
  810. X              Insert(MatchThisOrNext,status);
  811. X              Tail(status,Node(MatchThisOrNext));
  812. X              next_token=Node(MatchEmptyString);
  813. X              Tail(status,next_token);
  814. X              OpTail(status,next_token);
  815. X            }
  816. X  token++;
  817. X  if (MultipleMatches(*token))
  818. X    Fail("nested *?+");
  819. X  return(status);
  820. }
  821. X
  822. /*
  823. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  824. %                                                                             %
  825. %                                                                             %
  826. %                                                                             %
  827. %   R e g u l a r                                                             %
  828. %                                                                             %
  829. %                                                                             %
  830. %                                                                             %
  831. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  832. %
  833. %
  834. */
  835. static char *Regular(parenthesized,flagp)
  836. int
  837. X  parenthesized;
  838. X
  839. int
  840. X  *flagp;
  841. {
  842. X  int
  843. X    flags;
  844. X
  845. X  register char
  846. X    *br,
  847. X    *ender,
  848. X    *status;
  849. X
  850. X  register int
  851. X    count;
  852. X
  853. X  count=0;
  854. X  *flagp=NonNull;
  855. X  if (!parenthesized)
  856. X    status=NULL;
  857. X  else
  858. X    {
  859. X      /*
  860. X        Make an Open node.
  861. X      */
  862. X      if (number_parenthesis >= NumberSubExpressions)
  863. X        Fail("too many ()");
  864. X      count=number_parenthesis;
  865. X      number_parenthesis++;
  866. X      status=Node(Open+count);
  867. X    }
  868. X  /*
  869. X    Pick up the branches, linking them together.
  870. X  */
  871. X  br=Branch(&flags);
  872. X  if (br == NULL)
  873. X    return(NULL);
  874. X  if (status != NULL)
  875. X    Tail(status,br);
  876. X  else
  877. X    status=br;
  878. X  if (!(flags & NonNull))
  879. X    *flagp&=(~NonNull);
  880. X  *flagp|=flags & SpecialStart;
  881. X  while (*token == '|')
  882. X  {
  883. X    token++;
  884. X    br=Branch(&flags);
  885. X    if (br == NULL)
  886. X      return(NULL);
  887. X    Tail(status,br);
  888. X    if (!(flags & NonNull))
  889. X      *flagp &= ~NonNull;
  890. X    *flagp|=flags & SpecialStart;
  891. X  }
  892. X  /*
  893. X    Make a closing node and hook it on the end.
  894. X  */
  895. X  ender=Node((parenthesized) ? Close+count : EndOfProgram);
  896. X  Tail(status,ender);
  897. X  /*
  898. X    Hook the tails of the branches to the closing node.
  899. X  */
  900. X  for(br=status; br != NULL; br=NextToken(br))
  901. X    OpTail(br,ender);
  902. X  /*
  903. X    Check for proper termination.
  904. X  */
  905. X  if (parenthesized && (*token++ != ')'))
  906. X    Fail("unmatched()")
  907. X  else
  908. X    if (!parenthesized && (*token != '\0'))
  909. X      {
  910. X        if (*token == ')')
  911. X          Fail("unmatched()")
  912. X        else
  913. X          Fail("junk on end")
  914. X       }
  915. X  return(status);
  916. }
  917. X
  918. /*
  919. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  920. %                                                                             %
  921. %                                                                             %
  922. %                                                                             %
  923. %   R e p e a t                                                               %
  924. %                                                                             %
  925. %                                                                             %
  926. %                                                                             %
  927. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  928. %
  929. %
  930. */
  931. static int Repeat(p)
  932. char
  933. X  *p;
  934. {
  935. X  register char
  936. X    *operand,
  937. X    *scan;
  938. X
  939. X  register int
  940. X    count=0;
  941. X
  942. X  scan=p;
  943. X  operand=Operand(p);
  944. X  switch(OpCode(p))
  945. X  {
  946. X    case MatchAnyCharacter:
  947. X    {
  948. X      count=strlen(scan);
  949. X      scan+=count;
  950. X      break;
  951. X    }
  952. X    case MatchExactly:
  953. X    {
  954. X      while (*operand == *scan)
  955. X      {
  956. X        count++;
  957. X        scan++;
  958. X      }
  959. X      break;
  960. X    }
  961. X    case MatchAnyCharacterOf:
  962. X    {
  963. X      while ((*scan != '\0') && (strchr(operand,*scan) != NULL))
  964. X      {
  965. X        count++;
  966. X        scan++;
  967. X      }
  968. X      break;
  969. X    }
  970. X    case MatchAnyCharacterBut:
  971. X    {
  972. X      while ((*scan != '\0') && (strchr(operand,*scan) == NULL))
  973. X      {
  974. X        count++;
  975. X        scan++;
  976. X      }
  977. X      break;
  978. X    }
  979. X    default:
  980. X    {
  981. X      (void) fprintf(stderr,"Regular(3): %s","internal foulup");
  982. X      count=0;
  983. X      break;
  984. X    }
  985. X  }
  986. X  p=scan;
  987. X  return(count);
  988. }
  989. X
  990. /*
  991. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  992. %                                                                             %
  993. %                                                                             %
  994. %                                                                             %
  995. %   T a i l                                                                   %
  996. %                                                                             %
  997. %                                                                             %
  998. %                                                                             %
  999. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1000. %
  1001. %
  1002. */
  1003. static void Tail(p,val)
  1004. char
  1005. X  *p;
  1006. X
  1007. char
  1008. X  *val;
  1009. {
  1010. X  register char
  1011. X    *scan,
  1012. X    *temp;
  1013. X
  1014. X  register int
  1015. X    offset;
  1016. X
  1017. X  if (p == &start_code)
  1018. X    return;
  1019. X  /*
  1020. X    Find last node.
  1021. X  */
  1022. X  scan=p;
  1023. X  for(;;)
  1024. X  {
  1025. X    temp=NextToken(scan);
  1026. X    if (temp == NULL)
  1027. X      break;
  1028. X    scan=temp;
  1029. X  }
  1030. X  if (OpCode(scan) == Back)
  1031. X    offset=scan-val;
  1032. X  else
  1033. X    offset=val-scan;
  1034. X  *(scan+1)=(offset >> 8) & 0377;
  1035. X  *(scan+2)=offset & 0377;
  1036. }
  1037. X
  1038. /*
  1039. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1040. %                                                                             %
  1041. %                                                                             %
  1042. %                                                                             %
  1043. %   T r y                                                                     %
  1044. %                                                                             %
  1045. %                                                                             %
  1046. %                                                                             %
  1047. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1048. %
  1049. %
  1050. */
  1051. static int Try(regular_expression,pattern)
  1052. RegularExpression
  1053. X  *regular_expression;
  1054. X
  1055. char
  1056. X  *pattern;
  1057. {
  1058. X  register char
  1059. X    **ep,
  1060. X    **sp;
  1061. X
  1062. X  register int
  1063. X    i;
  1064. X
  1065. X  p=pattern;
  1066. X  subpattern=regular_expression->subpattern;
  1067. X  subpattern_end=regular_expression->subpattern_end;
  1068. X  sp=regular_expression->subpattern;
  1069. X  ep=regular_expression->subpattern_end;
  1070. X  for(i=NumberSubExpressions; i > 0; i--)
  1071. X  {
  1072. X    *sp++=NULL;
  1073. X    *ep++=NULL;
  1074. X  }
  1075. X  if (!Match(regular_expression->program+1))
  1076. X    return(0);
  1077. X  else
  1078. X    {
  1079. X      regular_expression->subpattern[0]=pattern;
  1080. X      regular_expression->subpattern_end[0]=p;
  1081. X      return(1);
  1082. X    }
  1083. }
  1084. X
  1085. /*
  1086. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1087. %                                                                             %
  1088. %                                                                             %
  1089. %                                                                             %
  1090. %   C o m p i l e R e g u l a r E x p r e s s i o n                           %
  1091. %                                                                             %
  1092. %                                                                             %
  1093. %                                                                             %
  1094. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1095. %
  1096. %  Function CompileRegularExpression compiles a regular expression into a
  1097. %  structure of type RegularExpression and returns a pointer to it.  The space
  1098. %  is allocated using function malloc and may be released by function free.
  1099. %
  1100. %
  1101. */
  1102. RegularExpression *CompileRegularExpression(regular_expression)
  1103. char
  1104. X  *regular_expression;
  1105. {
  1106. X  int
  1107. X    flags;
  1108. X
  1109. X  register char
  1110. X    *longest,
  1111. X    *scan;
  1112. X
  1113. X  register RegularExpression
  1114. X    *r;
  1115. X
  1116. X  register int
  1117. X    length;
  1118. X
  1119. X  if (regular_expression == NULL)
  1120. X    Fail("NULL argument");
  1121. X  /*
  1122. X    First pass: determine size.
  1123. X  */
  1124. X  token=regular_expression;
  1125. X  number_parenthesis=1;
  1126. X  code_size=0L;
  1127. X  code=(&start_code);
  1128. X  EmitCode(Magick);
  1129. X  if (Regular(0,&flags) == NULL)
  1130. X    return(NULL);
  1131. X  /*
  1132. X    Allocate space.
  1133. X  */
  1134. X  r=(RegularExpression *) malloc((code_size+sizeof(RegularExpression)));
  1135. X  if (r == (RegularExpression *) NULL)
  1136. X    Fail("out of space");
  1137. X  /*
  1138. X    Second pass: emit code.
  1139. X  */
  1140. X  token=regular_expression;
  1141. X  number_parenthesis=1;
  1142. X  code=r->program;
  1143. X  EmitCode(Magick);
  1144. X  if (Regular(0,&flags) == NULL)
  1145. X    return(NULL);
  1146. X  /*
  1147. X    Dig out information for optimizations.
  1148. X  */
  1149. X  r->start_character='\0';
  1150. X  r->anchor=0;
  1151. X  r->priority_pattern=NULL;
  1152. X  r->pattern_length=0;
  1153. X  scan=r->program+1;
  1154. X  if (OpCode(NextToken(scan)) == EndOfProgram)
  1155. X    {
  1156. X      scan=Operand(scan);
  1157. X      if (OpCode(scan) == MatchExactly)
  1158. X        r->start_character=(*Operand(scan));
  1159. X      else
  1160. X        if (OpCode(scan) == MatchBeginningOfLine)
  1161. X          r->anchor++;
  1162. X      /*
  1163. X        If there's something expensive in the regular expression, find the
  1164. X        longest literal pattern that must appear and make it the
  1165. X        priority_pattern.
  1166. X      */
  1167. X      if (flags & SpecialStart)
  1168. X        {
  1169. X          longest=NULL;
  1170. X          length=0;
  1171. X          for(; scan != NULL; scan=NextToken(scan))
  1172. X            if ((OpCode(scan) == MatchExactly) &&
  1173. X                (strlen(Operand(scan)) >= length))
  1174. X              {
  1175. X                longest=Operand(scan);
  1176. X                length=strlen(Operand(scan));
  1177. X              }
  1178. X          r->priority_pattern=longest;
  1179. X          r->pattern_length=length;
  1180. X        }
  1181. X    }
  1182. X  return(r);
  1183. }
  1184. X
  1185. /*
  1186. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1187. %                                                                             %
  1188. %                                                                             %
  1189. %                                                                             %
  1190. %   E x e c u t e R e g u l a r E x p r e s s i o n                           %
  1191. %                                                                             %
  1192. %                                                                             %
  1193. %                                                                             %
  1194. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1195. %
  1196. %  Function ExecuteRegularExpression matches a NULL-terminated pattern against
  1197. %  the compiled regular expression in regular-expression.  It returns 1 for
  1198. %  success and 0 for failure.
  1199. %
  1200. %
  1201. */
  1202. int ExecuteRegularExpression(regular_expression,pattern)
  1203. register RegularExpression
  1204. X  *regular_expression;
  1205. X
  1206. register char
  1207. X  *pattern;
  1208. {
  1209. X  register char
  1210. X    *s;
  1211. X
  1212. X  if ((regular_expression == (RegularExpression *) NULL) ||
  1213. X      (pattern == (char *) NULL))
  1214. X    {
  1215. X      (void) fprintf(stderr,"Regular(3): %s","NULL parameter\n");
  1216. X      return(0);
  1217. X    }
  1218. X  /*
  1219. X    Check validity of program.
  1220. X  */
  1221. X  if (((int)*(unsigned char *)(regular_expression->program)) != Magick)
  1222. X    {
  1223. X      (void) fprintf(stderr,"Regular(3): %s","corrupted program");
  1224. X      return(0);
  1225. X    }
  1226. X  /*
  1227. X    If there is a "must appear" pattern, look for it.
  1228. X  */
  1229. X  if (regular_expression->priority_pattern != NULL)
  1230. X    {
  1231. X      s=pattern;
  1232. X      while ((s=strchr(s,regular_expression->priority_pattern[0])) != NULL)
  1233. X      {
  1234. X        if (strncmp(s,regular_expression->priority_pattern,
  1235. X            regular_expression->pattern_length) == 0)
  1236. X          break;
  1237. X        s++;
  1238. X       }
  1239. X       if (s == NULL)
  1240. X         return(0);
  1241. X    }
  1242. X  /*
  1243. X    Mark beginning of line for ^.
  1244. X  */
  1245. X  start_pattern=pattern;
  1246. X  /*
  1247. X    Simplest case:  anchored match need be tried only once.
  1248. X  */
  1249. X  if (regular_expression->anchor)
  1250. X    return(Try(regular_expression,pattern));
  1251. X  /*
  1252. X    Messy cases:  unanchored match.
  1253. X  */
  1254. X  s=pattern;
  1255. X  if (regular_expression->start_character != '\0')
  1256. X    while ((s=strchr(s,regular_expression->start_character)) != NULL)
  1257. X    {
  1258. X      if (Try(regular_expression,s))
  1259. X        return(1);
  1260. X      s++;
  1261. X    }
  1262. X  else
  1263. X    do
  1264. X    {
  1265. X      if (Try(regular_expression,s))
  1266. X        return(1);
  1267. X    } while (*s++ != '\0');
  1268. X  return(0);
  1269. }
  1270. SHAR_EOF
  1271. echo 'File ImageMagick/xtp/regular.c is complete' &&
  1272. chmod 0644 ImageMagick/xtp/regular.c ||
  1273. echo 'restore of ImageMagick/xtp/regular.c failed'
  1274. Wc_c="`wc -c < 'ImageMagick/xtp/regular.c'`"
  1275. test 36656 -eq "$Wc_c" ||
  1276.     echo 'ImageMagick/xtp/regular.c: original size 36656, current size' "$Wc_c"
  1277. rm -f _shar_wnt_.tmp
  1278. fi
  1279. # ============= ImageMagick/xtp/regular.h ==============
  1280. if test -f 'ImageMagick/xtp/regular.h' -a X"$1" != X"-c"; then
  1281.     echo 'x - skipping ImageMagick/xtp/regular.h (File already exists)'
  1282.     rm -f _shar_wnt_.tmp
  1283. else
  1284. > _shar_wnt_.tmp
  1285. echo 'x - extracting ImageMagick/xtp/regular.h (Text)'
  1286. sed 's/^X//' << 'SHAR_EOF' > 'ImageMagick/xtp/regular.h' &&
  1287. /*
  1288. X  Definitions etc. for RegularExpression(3) routines.
  1289. */
  1290. #define EndOfProgram  0
  1291. #define MatchBeginningOfLine  1
  1292. #define MatchEndOfProgramOfLine  2
  1293. #define MatchAnyCharacter  3
  1294. #define MatchAnyCharacterOf  4
  1295. #define MatchAnyCharacterBut  5
  1296. #define MatchThisOrNext  6
  1297. #define Back  7
  1298. #define MatchExactly  8
  1299. #define MatchEmptyString  9
  1300. #define MatchZeroOrMore  10
  1301. #define MatchOneOrMore  11
  1302. #define Open  20
  1303. #define Close  30
  1304. X
  1305. #define WorstCase  0
  1306. #define NonNull  1
  1307. #define Simple  2
  1308. #define SpecialStart  4
  1309. X
  1310. #define Fail(m)  \
  1311. {  \
  1312. X  (void) fprintf(stderr,"RegularExpression: %s\n",m);  \
  1313. X  return(NULL);  \
  1314. }
  1315. #define Magick   0234
  1316. #define Meta  "^$.[()|?+*\\"
  1317. #define MultipleMatches(c) (((c) == '*') || ((c) == '+') || ((c) == '?'))
  1318. #define Next(p) (((*((p)+1) & 0377) << 8 )+(*((p)+2) & 0377))
  1319. #define NumberSubExpressions  10
  1320. #define OpCode(p) (*(p))
  1321. #define Operand(p) ((p)+3)
  1322. X
  1323. typedef struct _RegularExpression 
  1324. {
  1325. X  char 
  1326. X    *subpattern[NumberSubExpressions],
  1327. X    *subpattern_end[NumberSubExpressions],
  1328. X    start_character,
  1329. X    anchor,
  1330. X    *priority_pattern;
  1331. X
  1332. X  int 
  1333. X    pattern_length;
  1334. X
  1335. X  char 
  1336. X    program[1];
  1337. } RegularExpression;
  1338. X
  1339. extern RegularExpression 
  1340. X  *CompileRegularExpression _Declare((char *));
  1341. X
  1342. extern int 
  1343. X  ExecuteRegularExpression _Declare((RegularExpression *,char *));
  1344. SHAR_EOF
  1345. chmod 0644 ImageMagick/xtp/regular.h ||
  1346. echo 'restore of ImageMagick/xtp/regular.h failed'
  1347. Wc_c="`wc -c < 'ImageMagick/xtp/regular.h'`"
  1348. test 1299 -eq "$Wc_c" ||
  1349.     echo 'ImageMagick/xtp/regular.h: original size 1299, current size' "$Wc_c"
  1350. rm -f _shar_wnt_.tmp
  1351. fi
  1352. # ============= ImageMagick/xtp/xtp.c ==============
  1353. if test -f 'ImageMagick/xtp/xtp.c' -a X"$1" != X"-c"; then
  1354.     echo 'x - skipping ImageMagick/xtp/xtp.c (File already exists)'
  1355.     rm -f _shar_wnt_.tmp
  1356. else
  1357. > _shar_wnt_.tmp
  1358. echo 'x - extracting ImageMagick/xtp/xtp.c (Text)'
  1359. sed 's/^X//' << 'SHAR_EOF' > 'ImageMagick/xtp/xtp.c' &&
  1360. /*
  1361. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1362. %                                                                             %
  1363. %                                                                             %
  1364. %                                                                             %
  1365. %                            X   X  TTTTT PPPP                                %
  1366. %                             X X     T   P   P                               %
  1367. %                              X      T   PPPP                                %
  1368. %                             X X     T   P                                   %
  1369. %                            X   X    T   P                                   %
  1370. %                                                                             %
  1371. %                                                                             %
  1372. %                         File transfer program.                              %
  1373. %                                                                             %
  1374. %                                                                             %
  1375. %                                                                             %
  1376. %                           Software Design                                   %
  1377. %                             John Cristy                                     %
  1378. %                             October 1992                                    %
  1379. %                                                                             %
  1380. %                                                                             %
  1381. %  Copyright 1992 E. I. Dupont de Nemours & Company                           %
  1382. %                                                                             %
  1383. %  Permission to use, copy, modify, distribute, and sell this software and    %
  1384. %  its documentation for any purpose is hereby granted without fee,           %
  1385. %  provided that the above copyright notice appear in all copies and that     %
  1386. %  both that copyright notice and this permission notice appear in            %
  1387. %  supporting documentation, and that the name of E. I. Dupont de Nemours     %
  1388. %  & Company not be used in advertising or publicity pertaining to            %
  1389. %  distribution of the software without specific, written prior               %
  1390. %  permission.  E. I. Dupont de Nemours & Company makes no representations    %
  1391. %  about the suitability of this software for any purpose.  It is provided    %
  1392. %  "as is" without express or implied warranty.                               %
  1393. %                                                                             %
  1394. %  E. I. Dupont de Nemours & Company disclaims all warranties with regard     %
  1395. %  to this software, including all implied warranties of merchantability      %
  1396. %  and fitness, in no event shall E. I. Dupont de Nemours & Company be        %
  1397. %  liable for any special, indirect or consequential damages or any           %
  1398. %  damages whatsoever resulting from loss of use, data or profits, whether    %
  1399. %  in an action of contract, negligence or other tortious action, arising     %
  1400. %  out of or in connection with the use or performance of this software.      %
  1401. %                                                                             %
  1402. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1403. %
  1404. %  Xtp is a utility for retrieving, listing, or printing files from a
  1405. %  remote network site.  Xtp performs most of the same functions as the
  1406. %  FTP program, but does not require any interactive commands.  You simply
  1407. %  specify the file transfer task on the command line and xtp performs the
  1408. %  transfer automatically.
  1409. %
  1410. %  This program was adapted from a similiar program written by Steve Singles,
  1411. %  University of Delaware.
  1412. %
  1413. %  Command syntax:
  1414. %
  1415. %  Usage: xtp [-options ...] <host/ip address> [ <home directory> ]
  1416. %
  1417. %  Where options include:
  1418. %    -binary                retrieve files as binary
  1419. %    -exclude expression    exclude files that match the expression
  1420. %    -directory expression  list file names that match the expression
  1421. %    -ident password        specifies password
  1422. %    -port number           port number of FTP server
  1423. %    -print expression      print files that match the expression
  1424. %    -prune                 do not recursively search for files
  1425. %    -retrieve expression   retrieve files that match the expression
  1426. %    -send expression       send files that match the expression
  1427. %    -timeout seconds       specifies maximum seconds of XTP session
  1428. %    -user name             identify yourself to the remote FTP server
  1429. %
  1430. %
  1431. */
  1432. X
  1433. /*
  1434. X  Include declarations.
  1435. */
  1436. #define _POSIX_SOURCE  1
  1437. #include "xtp.h"
  1438. #include "regular.h"
  1439. #include <unistd.h>
  1440. #include <sys/types.h>
  1441. #include <signal.h>
  1442. #include <termios.h>
  1443. #include <fcntl.h>
  1444. #include <sys/stat.h>
  1445. #include <sys/wait.h>
  1446. /*
  1447. X  Variable declarations.
  1448. */
  1449. static char
  1450. X  *application_name,
  1451. X  slave_tty[16];
  1452. X
  1453. static int
  1454. X  master,
  1455. X  status;
  1456. X
  1457. static RegularExpression
  1458. X  *directory_expression,
  1459. X  *exclude_expression,
  1460. X  *print_expression,
  1461. X  *retrieve_expression;
  1462. X
  1463. /*
  1464. X  External declarations.
  1465. */
  1466. extern char
  1467. X  *GetHostInfo _Declare((char *));
  1468. X
  1469. /*
  1470. X  Forward declarations.
  1471. */
  1472. static char
  1473. X  *Wait _Declare((void));
  1474. X
  1475. static void
  1476. X  DirectoryRequest _Declare((char *, char *)),
  1477. X  PrintRequest _Declare((char *,unsigned int)),
  1478. X  RetrieveRequest _Declare((char *,unsigned int));
  1479. X
  1480. /*
  1481. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1482. %                                                                             %
  1483. %                                                                             %
  1484. %                                                                             %
  1485. %   D i r e c t o r y R e q u e s t                                           %
  1486. %                                                                             %
  1487. %                                                                             %
  1488. %                                                                             %
  1489. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1490. %
  1491. %  Function DirectoryRequest lists a file name and its attributes.
  1492. %
  1493. %  The format of the DirectoryRequest routine is:
  1494. %
  1495. %    DirectoryRequest(fileinfo,filename)
  1496. %
  1497. %  A description of each parameter follows:
  1498. %
  1499. %    o filename:  Specifies a pointer to a character array that contains
  1500. %      information about the file.
  1501. %
  1502. %    o filename:  Specifies a pointer to a character array that contains
  1503. %      the name of the file.
  1504. %
  1505. */
  1506. static void DirectoryRequest(fileinfo,filename)
  1507. char
  1508. X  *fileinfo,
  1509. X  *filename;
  1510. {
  1511. X  status=0;
  1512. X  if (*fileinfo == '\0')
  1513. X    (void) fprintf(stdout,"%s\n",filename);
  1514. X  else
  1515. X    (void) fprintf(stdout,"%s %s\n",fileinfo,filename);
  1516. }
  1517. X
  1518. /*
  1519. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1520. %                                                                             %
  1521. %                                                                             %
  1522. %                                                                             %
  1523. %   E r r o r                                                                 %
  1524. %                                                                             %
  1525. %                                                                             %
  1526. %                                                                             %
  1527. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1528. %
  1529. %  Function Error displays an error message and then terminates the program.
  1530. %
  1531. %  The format of the Error routine is:
  1532. %
  1533. %      Error(message,qualifier)
  1534. %
  1535. %  A description of each parameter follows:
  1536. %
  1537. %    o message: Specifies the message to display before terminating the
  1538. %      program.
  1539. %
  1540. %    o qualifier: Specifies any qualifier to the message.
  1541. %
  1542. %
  1543. */
  1544. void Error(message,qualifier)
  1545. char
  1546. X  *message,
  1547. X  *qualifier;
  1548. {
  1549. X  (void) fprintf(stderr,"%s: %s",application_name,message);
  1550. X  if (qualifier != (char *) NULL)
  1551. X    (void) fprintf(stderr," (%s)",qualifier);
  1552. X  (void) fprintf(stderr,".\n");
  1553. X  exit(1);
  1554. }
  1555. X
  1556. /*
  1557. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1558. %                                                                             %
  1559. %                                                                             %
  1560. %                                                                             %
  1561. %   E x e c u t e F t p                                                       %
  1562. %                                                                             %
  1563. %                                                                             %
  1564. %                                                                             %
  1565. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1566. %
  1567. %  Function ExecuteFtp executes the FTP program as a child process.
  1568. %
  1569. %  The format of the ExecuteFtp routine is:
  1570. %
  1571. %    ExecuteFtp(host_name,port)
  1572. %
  1573. %  A description of each parameter follows:
  1574. %
  1575. %    o host_name:  Specifies a pointer to a character array that contains the
  1576. %      name of the host to establish a connection to a FTP server.
  1577. %
  1578. %    o port:  Specifies a port number.  If the port number is NULL, xtp
  1579. %      attempts to contact a FTP server at the default port.
  1580. %
  1581. %
  1582. %
  1583. */
  1584. static void ExecuteFtp(host_name,port)
  1585. char
  1586. X  *host_name,
  1587. X  *port;
  1588. {
  1589. X  int
  1590. X    slave;
  1591. X
  1592. X  struct sigaction
  1593. X    action;
  1594. X
  1595. X  struct termios
  1596. X    attributes;
  1597. X
  1598. X  /*
  1599. X    Get slave tty line.
  1600. X  */
  1601. X  action.sa_handler=SIG_IGN;
  1602. X  (void) sigemptyset(&action.sa_mask);
  1603. X  action.sa_flags=0;
  1604. X  (void) sigaction(SIGTSTP,&action,(struct sigaction *) NULL);
  1605. X  if (isatty(STDIN_FILENO))
  1606. X    (void) setsid();
  1607. X  slave=open(slave_tty,O_RDWR | O_NOCTTY);
  1608. X  if (slave < 0)
  1609. X    Error("unable to open slave pseudo-terminal",slave_tty);
  1610. X  /*
  1611. X    Condition slave tty line.
  1612. X  */
  1613. X  (void) tcgetattr(slave,&attributes);
  1614. X  attributes.c_cflag|=HUPCL;
  1615. X  attributes.c_lflag&=(~(ICANON | ECHO));
  1616. X  attributes.c_oflag&=(~OPOST);
  1617. X  (void) tcflush(slave,TCIFLUSH);
  1618. X  (void) tcsetattr(slave,TCSANOW,&attributes);
  1619. X  /*
  1620. X    Execute FTP program as a child process.
  1621. X  */
  1622. X  (void) close(master);
  1623. X  (void) dup2(slave,STDIN_FILENO);
  1624. X  (void) dup2(slave,STDOUT_FILENO);
  1625. X  (void) dup2(slave,STDERR_FILENO);
  1626. X  (void) close(slave);
  1627. X  (void) execlp("ftp","ftp","-n","-i","-g","-v",host_name,port,(char *) 0);
  1628. X  perror("ftp");
  1629. X  (void) kill(0,SIGTERM);
  1630. }
  1631. X
  1632. /*
  1633. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1634. %                                                                             %
  1635. %                                                                             %
  1636. %                                                                             %
  1637. %   G e t P a s s w o r d                                                     %
  1638. %                                                                             %
  1639. %                                                                             %
  1640. %                                                                             %
  1641. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1642. %
  1643. %  Function GetPassword prompts the user for a password.  The password is
  1644. %  not echoed on the terminal.
  1645. %
  1646. %  The format of the GetPassword routine is:
  1647. %
  1648. %    password=GetPassword(prompt)
  1649. %
  1650. %  A description of each parameter follows:
  1651. %
  1652. %    o password:  Specifies a pointer to a character array that contains
  1653. %      accepted from the user.
  1654. %
  1655. %    o prompt:  Specifies a pointer to a character array that contains
  1656. %      a message to display to the user.
  1657. %
  1658. %
  1659. */
  1660. static char *GetPassword(prompt)
  1661. char
  1662. X  *prompt;
  1663. {
  1664. X  static char
  1665. X    password[2048];
  1666. X
  1667. X  struct termios
  1668. X    attributes;
  1669. X
  1670. X  (void) fprintf(stdout,"%s",prompt);
  1671. X  (void) fflush(stdout);
  1672. X  (void) tcgetattr(STDIN_FILENO,&attributes);
  1673. X  attributes.c_lflag&=(~ECHO);
  1674. X  (void) tcsetattr(STDIN_FILENO,TCSANOW,&attributes);
  1675. X  gets(password);
  1676. X  attributes.c_lflag|=ECHO;
  1677. X  (void) tcsetattr(STDIN_FILENO,TCSANOW,&attributes);
  1678. X  (void) fprintf(stdout,"\n");
  1679. X  return(password);
  1680. }
  1681. X
  1682. /*
  1683. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1684. %                                                                             %
  1685. %                                                                             %
  1686. %                                                                             %
  1687. %   G e t P s e u d o T e r m i n a l                                         %
  1688. %                                                                             %
  1689. %                                                                             %
  1690. %                                                                             %
  1691. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1692. %
  1693. %  Function GetPseudoTerminal returns a master/slave pair of pseudo-terminals.
  1694. %
  1695. %  The format of the GetPseudoTerminal routine is:
  1696. %
  1697. %    GetPseudoTerminal()
  1698. %
  1699. %
  1700. */
  1701. static void GetPseudoTerminal()
  1702. {
  1703. X  char
  1704. X    master_tty[16];
  1705. X
  1706. X  register char
  1707. X    *bank,
  1708. X    *cp;
  1709. X
  1710. X  struct stat
  1711. X    info;
  1712. X
  1713. X  for (bank="pqrs"; *bank; bank++)
  1714. X  {
  1715. X    (void) sprintf(master_tty,"/dev/pty%c0",*bank);
  1716. X    if (stat(master_tty,&info) < 0)
  1717. X      break;
  1718. X    for (cp="0123456789abcdef"; *cp; cp++)
  1719. X    {
  1720. X      (void) sprintf((char *) master_tty,"/dev/pty%c%c",*bank,*cp);
  1721. X      master=open(master_tty,O_RDWR);
  1722. X      if (master >= 0)
  1723. X        {
  1724. X          /*
  1725. X            Verify slave side is usable.
  1726. X          */
  1727. X          (void) sprintf(slave_tty,"/dev/tty%c%c",*bank,*cp);
  1728. X          if (access(slave_tty,R_OK | W_OK) == 0)
  1729. X            {
  1730. X              struct termios
  1731. X                attributes;
  1732. X
  1733. X              /*
  1734. X                Condition master tty line.
  1735. X              */
  1736. X              (void) tcgetattr(master,&attributes);
  1737. X              attributes.c_lflag&=(~(ICANON | ECHO));
  1738. X              (void) tcsetattr(master,TCSANOW,&attributes);
  1739. X              return;
  1740. X            }
  1741. X          (void) close(master);
  1742. X        }
  1743. X    }
  1744. X  }
  1745. X  Error("All network ports in use",(char *) NULL);
  1746. }
  1747. X
  1748. /*
  1749. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1750. %                                                                             %
  1751. %                                                                             %
  1752. %                                                                             %
  1753. %   M a k e D i r e c t o r y                                                 %
  1754. %                                                                             %
  1755. %                                                                             %
  1756. %                                                                             %
  1757. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1758. %
  1759. %  Function MakeDirectory checks each component of a directory path and if it
  1760. %  does not exist, creates it.
  1761. %
  1762. %  The format of the MakeDirectory routine is:
  1763. %
  1764. %    MakeDirectory(directory)
  1765. %
  1766. %  A description of each parameter follows:
  1767. %
  1768. %    o directory:  Specifies a pointer to a character array that contains
  1769. %      the name of the directory to create.
  1770. %
  1771. %
  1772. */
  1773. static int MakeDirectory(directory)
  1774. char
  1775. X  *directory;
  1776. {
  1777. X  register char
  1778. X    *p;
  1779. X
  1780. X  struct stat
  1781. X    info;
  1782. X
  1783. X  /*
  1784. X    Determine first component of the directory.
  1785. X  */
  1786. X  p=strrchr(directory,'/');
  1787. X  if ((p == (char *) NULL) || (p == directory))
  1788. X    return(False);
  1789. X  *p='\0';
  1790. X  if (lstat(directory,&info) < 0)
  1791. X    {
  1792. X      /*
  1793. X        Path component does not exist;  create it.
  1794. X      */
  1795. X      if (MakeDirectory(directory) == 0)
  1796. X        if (mkdir(directory,(mode_t) 0777) >= 0)
  1797. X          {
  1798. X            *p='/';
  1799. X            return(False);
  1800. X          }
  1801. X    }
  1802. X  else
  1803. X    if (S_ISDIR(info.st_mode))
  1804. X      {
  1805. X        /*
  1806. X          Path component already exists.
  1807. X        */
  1808. X        *p='/';
  1809. X        return(False);
  1810. X      }
  1811. X  /*
  1812. X    Path component is a file not a directory.
  1813. X  */
  1814. X  *p='/';
  1815. X  return(True);
  1816. }
  1817. X
  1818. /*
  1819. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1820. %                                                                             %
  1821. %                                                                             %
  1822. %                                                                             %
  1823. %   P r i n t R e q u e s t                                                   %
  1824. %                                                                             %
  1825. %                                                                             %
  1826. %                                                                             %
  1827. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1828. %
  1829. %  Function PrintRequest prints a file on the remote FTP server.
  1830. %
  1831. %  The format of the PrintRequest routine is:
  1832. %
  1833. %    PrintRequest(filename,verbose)
  1834. %
  1835. %  A description of each parameter follows:
  1836. %
  1837. %    o filename:  Specifies a pointer to a character array that contains
  1838. %      the name of the file to print.
  1839. %
  1840. %    o verbose: An unsigned integer.  A value other than zero dhows all
  1841. %      responses from the remote server.
  1842. %
  1843. %
  1844. */
  1845. static void PrintRequest(filename,verbose)
  1846. char
  1847. X  *filename;
  1848. X
  1849. unsigned int
  1850. X  verbose;
  1851. {
  1852. X  char
  1853. X    command[2048],
  1854. X    *response;
  1855. X
  1856. X  /*
  1857. X    get remote-file [ - | < |zcat > ].
  1858. X  */
  1859. X  (void) sprintf(command,"get %s",filename);
  1860. X  if (strcmp(filename+strlen(filename)-2,".Z"))
  1861. X    (void) strcat(command," -\r");
  1862. X  else
  1863. X    (void) strcat(command," |zcat\r");
  1864. X  (void) write(master,command,strlen(command));
  1865. X  (void) fprintf(stdout,"%s:\n",filename);
  1866. X  while (response=Wait())
  1867. X    if (status == 0)
  1868. X      (void) fprintf(stdout,"%s\n",response);
  1869. X    else
  1870. X      if ((status == 5) || verbose)
  1871. X        (void) fprintf(stderr,"%s\n",response);
  1872. }
  1873. X
  1874. /*
  1875. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1876. %                                                                             %
  1877. %                                                                             %
  1878. %                                                                             %
  1879. %   P r o c e s s R e q u e s t                                               %
  1880. %                                                                             %
  1881. %                                                                             %
  1882. %                                                                             %
  1883. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1884. %
  1885. %  Function ProcessRequest first records any file in the current directory
  1886. %  of the remote FTP server or any of its subdirectories.  Next each filename
  1887. %  is either accepted or rejected based on a user specified regular
  1888. %  expresssion.  If any files match the regular expression, its filename is
  1889. %  listed, it is printed, or it is retrieved as specified on the command line.
  1890. %
  1891. %  The format of the ProcessRequest routine is:
  1892. %
  1893. %    ProcessRequest(prune,verbose)
  1894. SHAR_EOF
  1895. true || echo 'restore of ImageMagick/xtp/xtp.c failed'
  1896. fi
  1897. echo 'End of  part 3'
  1898. echo 'File ImageMagick/xtp/xtp.c is continued in part 4'
  1899. echo 4 > _shar_seq_.tmp
  1900. exit 0
  1901. exit 0 # Just in case...
  1902.