home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume17 / parseargs / part09 < prev    next >
Internet Message Format  |  1991-03-18  |  63KB

  1. From: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
  2. Newsgroups: comp.sources.misc
  3. Subject: v17i054:  parseargs - functions to parse command line arguments, Part09/12
  4. Message-ID: <1991Mar18.155707.2176@sparky.IMD.Sterling.COM>
  5. Date: 18 Mar 91 15:57:07 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: 5c2e25a2 b3a18d0f 8698d8b5 d41be7ad
  8.  
  9. Submitted-by: Brad Appleton <brad@hcx1.ssd.csd.harris.com>
  10. Posting-number: Volume 17, Issue 54
  11. Archive-name: parseargs/part09
  12.  
  13. This is part 9 of parseargs
  14.  
  15. #!/bin/sh
  16. # this is Part.09 (part 9 of a multipart archive)
  17. # do not concatenate these parts, unpack them in order with /bin/sh
  18. # file parseargs/pgopen.c continued
  19. #
  20. if test ! -r _shar_seq_.tmp; then
  21.     echo 'Please unpack part 1 first!'
  22.     exit 1
  23. fi
  24. (read Scheck
  25.  if test "$Scheck" != 9; then
  26.     echo Please unpack part "$Scheck" next!
  27.     exit 1
  28.  else
  29.     exit 0
  30.  fi
  31. ) < _shar_seq_.tmp || exit 1
  32. if test ! -f _shar_wnt_.tmp; then
  33.     echo 'x - still skipping parseargs/pgopen.c'
  34. else
  35. echo 'x - continuing file parseargs/pgopen.c'
  36. sed 's/^X//' << 'SHAR_EOF' >> 'parseargs/pgopen.c' &&
  37. **    pager-file-pointer.
  38. **
  39. ** ^SIDE-EFECTS:
  40. **    None.
  41. **
  42. ** ^RETURN-VALUE:
  43. **    Zero if the pager is active; non-zero otherwise.
  44. **
  45. ** ^ALGORITHM:
  46. **    Trivial.
  47. ***^^**********************************************************************/
  48. #ifdef __ANSI_C__
  49. X   int pgactive( const FILE *pager_fp )
  50. #endif
  51. {
  52. X   return  ( (Pager_Type != PG_CLOSED)  &&  (pager_fp) );
  53. }
  54. X
  55. X
  56. /***************************************************************************
  57. ** ^FUNCTION: pgclose - close the pager.
  58. **
  59. ** ^SYNOPSIS:
  60. */
  61. #ifndef __ANSI_C__
  62. X   int pgclose( pager_fp )
  63. /*
  64. ** ^PARAMETERS:
  65. */
  66. X   FILE *pager_fp;
  67. /*    -- the file-pointer returned by pgopen()
  68. */
  69. #endif  /* !__ANSI_C__ */
  70. X
  71. /* ^DESCRIPTION:
  72. **    Pgclose will flush any remaining output and close the pager.
  73. **
  74. ** ^REQUIREMENTS:
  75. **    pgopen() must first be called in order to obtain a valid
  76. **    pager-file-pointer.
  77. **
  78. ** ^SIDE-EFECTS:
  79. **    None.
  80. **
  81. ** ^RETURN-VALUE:
  82. **    Returns 0 if the pager was succesfully close; non-zero if it wasnt
  83. **    in use to begin with.
  84. **
  85. ** ^ALGORITHM:
  86. **    - if ( pager-not-in-use )  return 1
  87. **    - flush any remaining pager output
  88. **    - if we used popen() to open this pager then
  89. **       - call pclose to close the pager-program
  90. **       - unset the SIGPIPE signal-handler
  91. **       - wait for the pager-process to die
  92. **      end-if
  93. **    - reset the pager-file-pointer to NULL
  94. **    - set the pager-state to closed
  95. **    - return 0
  96. ***^^**********************************************************************/
  97. #ifdef __ANSI_C__
  98. X   int pgclose( FILE *pager_fp )
  99. #endif
  100. {
  101. X   if ( Pager_Type == PG_CLOSED  ||  !Pager_FP  ||  !pager_fp )  return  1;
  102. X
  103. X   fflush( Pager_FP );
  104. X
  105. X   if ( Pager_Type == PG_ENV  ||  Pager_Type == PG_DFLT ) {
  106. X      signal( SIGPIPE, (void (*)())SIG_IGN );
  107. X      wait( (int *) 0 );
  108. X   }
  109. X
  110. X   Pager_FP = (FILE *)NULL;
  111. X   Pager_Type = PG_CLOSED;
  112. X
  113. X   return  0;
  114. }
  115. X
  116. X
  117. /***************************************************************************
  118. ** ^FUNCTION: pgopen - open the pager
  119. **
  120. ** ^SYNOPSIS:
  121. */
  122. #ifndef __ANSI_C__
  123. X   FILE *pgopen( fp, pager_cmd )
  124. /*
  125. ** ^PARAMETERS:
  126. */
  127. X   FILE *fp;
  128. /*    -- the file pointer to use if popen() fails
  129. */
  130. X   char *pager_cmd;
  131. /*    -- name of the pager-program to pass to popen()
  132. */
  133. #endif  /* !__ANSI_C__ */
  134. X
  135. /* ^DESCRIPTION:
  136. **    Pgopen will attempt to "redirect" output from the given file
  137. **    pointer to the pager specified by <pager_cmd>.  If <fp> is NOT
  138. **    connected to a terminal or <pager_cmd> cannot be succesfully
  139. **    opened, then <fp> is resturned output is sent to it unpaginated.
  140. **    Otherwise, pgopen will try to open <pager_cmd> for input. If it
  141. **    cannot succeed it tries to open $PAGER for input. If this also
  142. **    fails then /usr/ucb/more is tried. If all else fails, return <fp>.
  143. **
  144. ** ^REQUIREMENTS:
  145. **    pager_cmd should be the full-pathname name of a valid, executable
  146. **    program which reads from standard input and writes (one screenful
  147. **    at a time) to the terminal.
  148. **
  149. ** ^SIDE-EFECTS:
  150. **    If popen() succeeds, the SIGPIPE signal is trapped.
  151. **
  152. ** ^RETURN-VALUE:
  153. **    returns 0 upon success, non-zero if the pager is already in use.
  154. **
  155. ** ^ALGORITHM:
  156. **    - if the pager is already in use, return 1
  157. **    - if <fp> is not connected to a terminal, use it for output and return 0
  158. **    - set up recovery point for SIGPIPE signal
  159. **    - if we can open the pager_cmd, check for a SIGPIPE error
  160. **    - if either of the above fails, then try the same with $PAGER
  161. **    - if either of the above fails, then try the same with /usr/ucb/more
  162. **    - if either of the above fails, just use <fp> and return
  163. ***^^**********************************************************************/
  164. #ifdef __ANSI_C__
  165. X   FILE *pgopen( FILE *fp, const char *pager_cmd )
  166. #endif
  167. {
  168. X   pager_t  pg_type;
  169. X   char     pg_name[ MAX_NAME_LEN ];
  170. X
  171. X      /* if a pager is already open - ignore this call */
  172. X   if ( Pager_Type != PG_CLOSED  ||  Pager_FP )  return  fp;
  173. X
  174. X      /*
  175. X      ** dont page output if it has been redirected
  176. X      */
  177. X   if ( !isTERMINAL(fileno(fp)) ) {
  178. X      Pager_Type = PG_FILE;
  179. X      Pager_FP = fp;
  180. X      return  fp;
  181. X   }
  182. X
  183. X   *pg_name = '\0';
  184. X   if ( pager_cmd )  strcpy( pg_name, pager_cmd );
  185. X   pg_type = pg_pathname( pg_name );
  186. X   Pager_FP = (FILE *)NULL;
  187. X
  188. X      /* jump here after pg_error fields SIGPIPE */
  189. X   if ( setjmp( pg_recover ) ) {
  190. X      (void) pclose( Pager_FP );
  191. X      Pager_FP = (FILE *)NULL;
  192. X      pg_type = ( pg_type == PG_ENV ) ? PG_DFLT : PG_NONE;
  193. X   }
  194. X
  195. X      /* keep trying till we get a valid file-pointer */
  196. X   while ( !Pager_FP ) {
  197. X      switch( pg_type ) {
  198. X         case PG_DFLT:
  199. X               /* jump here if both $PAGER and DEFAULT-PAGER fail */
  200. X            if ( setjmp( pg_recover )) {
  201. X               (void) pclose( Pager_FP );
  202. X               Pager_FP = (FILE *)NULL;
  203. X               pg_type = PG_NONE;
  204. X               continue;
  205. X            }
  206. X               /* fall through to next case */
  207. X
  208. X         case PG_ENV:
  209. X            signal( SIGPIPE, pg_error );
  210. X            Pager_FP = (FILE *) popen( pg_name, "w" );
  211. X            if ( !Pager_FP ) {
  212. X               if ( pg_type == PG_ENV ) {
  213. X                  Pager_FP = (FILE *)NULL;
  214. X                  pg_type = PG_DFLT;
  215. X               }
  216. X               else {
  217. X                  Pager_FP = fp;
  218. X                  pg_type = PG_NONE;
  219. X               }
  220. X            }
  221. X            else {
  222. X                  /*
  223. X                  ** Sleep for a bit, just so we block, and the child
  224. X                  ** process can get moving. Then attempt to write to
  225. X                  ** the pager pipeline. If the pager is bad then the
  226. X                  ** pipe will be broken and pg_error() will handle
  227. X                  ** the broken-pipe signal. Othwerwise, the write will
  228. X                  ** succeed and we'll reset the handler to ignore the
  229. X                  ** broken pipe signal.
  230. X                  */
  231. X               sleep( 1 );
  232. X               fputc( '\n', Pager_FP );
  233. X               fflush( Pager_FP );
  234. X               signal( SIGPIPE, (void (*)())SIG_IGN );
  235. X            }
  236. X            break;
  237. X
  238. X         case PG_NONE:
  239. X         case PG_FILE:
  240. X            Pager_FP = fp;
  241. X            break;
  242. X
  243. X         default:
  244. X            fprintf( stderr, "Unrecognized state [%d] in pgopen()\n",
  245. X                     pg_type );
  246. X            exit( -1 );
  247. X      }/*switch*/
  248. X   }/*while*/
  249. X
  250. X   Pager_Type = pg_type;
  251. X   return  Pager_FP;
  252. }
  253. X
  254. X
  255. /***************************************************************************
  256. ** ^FUNCTION: pg_error - handle error when trying to open a pager
  257. **
  258. ** ^SYNOPSIS:
  259. */
  260. #ifndef __ANSI_C__
  261. X   static void pg_error()
  262. #endif
  263. /*
  264. ** ^PARAMETERS:
  265. **    None.
  266. **
  267. ** ^DESCRIPTION:
  268. **    Pgerror is called when the SIGPIPE signal is recieved. If SIGPIPE
  269. **    is recieved, it means that popen succesfully forked the shell to
  270. **    run the pager but the pager-command itself broke the read-end of
  271. **    the pipe between us (i.e. it is an invalid pager-program or it crashed).
  272. **
  273. **    When SIGPIPE is recieved, this routine will reset the signal handler
  274. **    to its previous value and jump to the recovery point set up by pgopen.
  275. **
  276. ** ^REQUIREMENTS:
  277. **    Pgopen must set up this function is the SIGPIPE handler function.
  278. **
  279. **    Pgopen must place the address of the desired recovery point in
  280. **    pg_recover.
  281. **
  282. ** ^SIDE-EFECTS:
  283. **    Resets SIGPIPE signal-handler and performs a non-local goto.
  284. **
  285. ** ^RETURN-VALUE:
  286. **    None.
  287. **
  288. ** ^ALGORITHM:
  289. **    Trivial.
  290. ***^^**********************************************************************/
  291. #ifdef __ANSI_C__
  292. X   static void pg_error( void )
  293. #endif
  294. {
  295. X   signal( SIGPIPE, (void (*)())SIG_IGN );
  296. X   longjmp( pg_recover, 1 );
  297. }
  298. X
  299. X
  300. /***************************************************************************
  301. ** ^FUNCTION: pg_pathname - get name of pager-program to use
  302. **
  303. ** ^SYNOPSIS:
  304. */
  305. #ifndef __ANSI_C__
  306. X   static pager_t pg_pathname( pager_cmd )
  307. /*
  308. ** ^PARAMETERS:
  309. */
  310. X   char *pager_cmd;
  311. /*    -- name of the pager-program to verify
  312. */
  313. #endif  /* !__ANSI_C__ */
  314. /* ^DESCRIPTION:
  315. **    Pg_pathname will determine the name of the pager-program to attempt to
  316. **    open based on the values of pager_cmd, and $PAGER.
  317. **
  318. ** ^REQUIREMENTS:
  319. **    pager_cmd must be non-null and be large enough to hold any of the
  320. **    possible pager program-names to be opened.
  321. **
  322. ** ^SIDE-EFECTS:
  323. **    pager_cmd is over-written with the name of the pager-command to
  324. **    try to open for output
  325. **
  326. ** ^RETURN-VALUE:
  327. **    Returns PG_DFLT if /usr/ucb/more is to be used.
  328. **    Returns PG_ENV if $PAGER or <pager_cmd> is to be used.
  329. **
  330. ** ^ALGORITHM:
  331. **    - If pager_cmd is executable then compare it to /usr/ucb/more
  332. **        return PG_ENV if not-equal, else return PG_DFLT
  333. **    - Else
  334. **      - pager_cmd = $PAGER
  335. **      - If $PAGER is executable then compare it to /usr/ucb/more
  336. **          return PG_ENV if not-equal, else return PG_DFLT
  337. **      - Else
  338. **          pager_cmd = /usr/ucb/more
  339. **          return  PG_DFLT
  340. **        End-if
  341. **      End-if
  342. ***^^**********************************************************************/
  343. #ifdef __ANSI_C__
  344. X   static pager_t  pg_pathname( char *pager_cmd )
  345. #endif
  346. {
  347. X   char      *pg_name = pager_cmd, *getenv();
  348. X   pager_t   pg_type;
  349. X
  350. X   if ( Pager_Type != PG_NONE )   pg_type = Pager_Type;
  351. X
  352. X      /* see if the given pager is okay */
  353. X   if ( !pg_name  ||  !*pg_name  ||  !access(pg_name, X_OK) ) {
  354. X      pg_name = getenv("PAGER");
  355. X   }
  356. X   else {
  357. X      pg_type = ( strcmp(pager_cmd, DEFAULT_PAGER) ) ? PG_ENV : PG_DFLT;
  358. X      return   pg_type;
  359. X   }
  360. X
  361. X      /* see if $PAGER is ok */
  362. X   if ( !access(pg_name, X_OK) ) {
  363. X      pg_type = ( strcmp(pg_name, DEFAULT_PAGER) ) ? PG_ENV : PG_DFLT;
  364. X      strcpy( pager_cmd, pg_name );
  365. X   }
  366. X   else {
  367. X      pg_type = PG_DFLT;
  368. X      strcpy( pager_cmd, DEFAULT_PAGER );
  369. X   }
  370. X
  371. X   return   pg_type;
  372. }/* pg_pathname */
  373. X
  374. X
  375. #endif  /* USE_PAGER */
  376. SHAR_EOF
  377. echo 'File parseargs/pgopen.c is complete' &&
  378. chmod 0664 parseargs/pgopen.c ||
  379. echo 'restore of parseargs/pgopen.c failed'
  380. Wc_c="`wc -c < 'parseargs/pgopen.c'`"
  381. test 12588 -eq "$Wc_c" ||
  382.     echo 'parseargs/pgopen.c: original size 12588, current size' "$Wc_c"
  383. rm -f _shar_wnt_.tmp
  384. fi
  385. # ============= parseargs/pgopen.h ==============
  386. if test -f 'parseargs/pgopen.h' -a X"$1" != X"-c"; then
  387.     echo 'x - skipping parseargs/pgopen.h (File already exists)'
  388.     rm -f _shar_wnt_.tmp
  389. else
  390. > _shar_wnt_.tmp
  391. echo 'x - extracting parseargs/pgopen.h (Text)'
  392. sed 's/^X//' << 'SHAR_EOF' > 'parseargs/pgopen.h' &&
  393. /*************************************************************************
  394. ** ^FILE: pgopen.h - include file for pgopen.c
  395. **
  396. ** ^DESCRIPTION:
  397. **    If USE_PAGER is #define'd then this file will define the function
  398. **    prototypes needed to use the paging library implemented in pgopen.c;
  399. **    Otherwise it will #define macros with the same name as the paging
  400. **    library routines which do NOT perform any paging.
  401. **
  402. ** ^HISTORY:
  403. **    01/02/91     Brad Appleton     <brad@ssd.csd.harris.com>     Created
  404. ***^^**********************************************************************/
  405. X
  406. #ifndef NULL
  407. #  include <stdio.h>
  408. #endif
  409. #include <useful.h>
  410. X
  411. #ifdef  USE_PAGER
  412. X   EXTERN   FILE *pgopen    ARGS(( FILE *, const char * ));
  413. X   EXTERN   int   pgclose   ARGS(( FILE * ));
  414. X   EXTERN   int   pgactive  ARGS(( const FILE * ));
  415. #else
  416. #  define  pgopen(fp,s)  (( !fp ) ? fp : (fflush(fp), fp))
  417. #  define  pgclose(fp)   (( !fp ) ?  0 : (fflush(fp), 0))
  418. #  define  pgactive(fp)  ( fp )
  419. #endif
  420. SHAR_EOF
  421. chmod 0664 parseargs/pgopen.h ||
  422. echo 'restore of parseargs/pgopen.h failed'
  423. Wc_c="`wc -c < 'parseargs/pgopen.h'`"
  424. test 977 -eq "$Wc_c" ||
  425.     echo 'parseargs/pgopen.h: original size 977, current size' "$Wc_c"
  426. rm -f _shar_wnt_.tmp
  427. fi
  428. # ============= parseargs/stest.c ==============
  429. if test -f 'parseargs/stest.c' -a X"$1" != X"-c"; then
  430.     echo 'x - skipping parseargs/stest.c (File already exists)'
  431.     rm -f _shar_wnt_.tmp
  432. else
  433. > _shar_wnt_.tmp
  434. echo 'x - extracting parseargs/stest.c (Text)'
  435. sed 's/^X//' << 'SHAR_EOF' > 'parseargs/stest.c' &&
  436. /*************************************************************************
  437. ** ^FILE: stest.c - test program for parseargs()
  438. **
  439. ** ^DESCRIPTION:
  440. **    This file is the test program for the parseargs(3) function libarary.
  441. **    It is used to test parseargs for all command-line styles (which presently
  442. **    includes: UNIX, VMS, AmigaDOS, MS-DOS, and OS/2).
  443. **
  444. ** ^HISTORY:
  445. **    --/--/--    Brad Appleton    <brad@ssd.csd.harris.com>    
  446. **    - Added structured block comments
  447. **    - Added an extra test for both old-style and new-style argument arrays
  448. **    - Added a test for triggers (ARGNOVAL arguments)
  449. **    - Added a test for arguments with optional values (using parsecntl())
  450. **    - Added arg-vector arguments
  451. **
  452. **    --/--/--    Peter da Silva    <peter@ferranti.com>    
  453. **
  454. **    --/--/--    Eric P. Allman    <eric@Berkeley.EDU>     Created
  455. ***^^**********************************************************************/
  456. X
  457. #include <useful.h>
  458. #include <parseargs.h>
  459. X
  460. VERSIONID("$Header: stest.c,v 2.0 89/12/24 00:56:29 eric Exp $");
  461. X
  462. static char Mode[4] = "OFF";
  463. X
  464. /***************************************************************************
  465. ** ^FUNCTION: argMine - example ARGNOVAL argument translation routine
  466. **
  467. ** ^SYNOPSIS:
  468. */
  469. #ifndef __ANSI_C__
  470. X   BOOL argMine( ad, vp, copyf )
  471. /*
  472. ** ^PARAMETERS:
  473. */
  474. X   ARGDESC *ad;
  475. /*    -- the argument descriptor for this parameter.
  476. */
  477. X   char *vp;
  478. /*    -- a pointer to the string input value.
  479. */
  480. X   BOOL copyf;
  481. /*    -- if TRUE, the value will be destroyed later, and so should be
  482. **       copied if it will be retained (as for a string).
  483. */
  484. #endif  /* !__ANSI_C__ */
  485. X
  486. /* ^DESCRIPTION:
  487. **    This routine is provided as a (very) simple example of how to use
  488. **    the ARGNOVAL flag to set up "trigger" arguments. Depending upon the
  489. **    implementation of the "trigger" function (this routine), the position
  490. **    of the corresponding argument on the command line may (or may not) be
  491. **    important.
  492. **
  493. ** ^REQUIREMENTS:
  494. **    ad should have ARGNOVAL set and this function as its ad_type.
  495. **
  496. ** ^SIDE-EFFECTS:
  497. **    The static global variable Mode is (re)written.
  498. **
  499. ** ^RETURN-VALUE:
  500. **    TRUE.
  501. **
  502. ** ^ALGORITHM:
  503. **    Trivial.
  504. ***^^**********************************************************************/
  505. /*ARGSUSED*/
  506. #ifdef __ANSI_C__
  507. X   BOOL argMine( ARGDESC *ad, char *vp, BOOL copyf )
  508. #endif
  509. {
  510. X   strcpy(Mode, "ON");
  511. X   return TRUE;
  512. }
  513. X
  514. /*************************************************************************/
  515. X   /* declare variables to hold values from the command-line */
  516. #define DEF_STR "Default String"
  517. X
  518. typedef ARGVEC_T(char *)  strvec_t;
  519. X
  520. static int    RepCount;
  521. static char    *Name;
  522. static char    *Str     = DEF_STR;
  523. static char    *DirName = ".";
  524. static BOOL    XRated   = FALSE;
  525. static BOOL    XFlag    = FALSE;
  526. static BOOL    YFlag    = TRUE;
  527. static BOOL    ZFlag    = FALSE;
  528. static char    TabChar  = ':';
  529. static ARGVEC_T(int) Integers = ARGVEC_EMPTY(int);
  530. static strvec_t Groups = ARGVEC_EMPTY(char *);
  531. static ArgList  *Argv  = (ArgList *)NULL;
  532. X
  533. /*************************************************************************/
  534. X   /* declare a new style argument-descriptor array */
  535. static
  536. CMD_OBJECT
  537. X   Cmd
  538. X
  539. CMD_NAME
  540. X   "stest -- test program for parseargs"
  541. X
  542. CMD_DESCRIPTION
  543. X   "This program is used to test parseargs for each desired command-line \
  544. style and for both old and new style argument-array declarations.  The actual \
  545. name of the command will be <os>_test.  parseargs will be called twice (with \
  546. the same command-line description) in order to test both the old and the new \
  547. syntax for declaring argument arrays."
  548. X
  549. CMD_ARGUMENTS
  550. X   'n', ARGREQ|ARGPOS, argStr,  __ &Name,  "name (name to look for)",
  551. X   's', ARGVALOPT, argStr,  __ &Str,       "STRing (optional string to use)",
  552. X   'g', ARGVEC,    argStr,  __ &Groups,    "newsGROUPS (newsgroups to test)",
  553. X   'c', ARGOPT,    argInt,  __ &RepCount,  "REPcount (repeat count per group)",
  554. X   'd', ARGOPT,    argStr,   __ &DirName,  "DIRname (work directory)",
  555. X   'i', ARGVEC,    argInt,   __ &Integers, "INTegerS (vector of numbers)",
  556. X   '#', ARGHIDDEN, argBool,  __ &XRated,   "XratedMODE (naughty! naughty!)",
  557. X
  558. X   'x', ARGOPT, argSBool, __ &XFlag, "Xflag (set X flag)",
  559. X   'y', ARGOPT, argUBool, __ &YFlag, "Yflag (unset Y flag)",
  560. X   'z', ARGOPT, argTBool, __ &ZFlag, "Zflag (toggle Z flag)",
  561. X
  562. X   't', ARGOPT,   argChar, __ &TabChar, "TABchar (field delimiter)",
  563. X   'r', ARGNOVAL, argMine, __ NULL,     "raw (trigger raw-mode \
  564. before processing any more arguments on the command-line)",
  565. X
  566. X   ' ', ARGLIST, listStr, __ &Argv, "file (list of files)",
  567. X
  568. X   END_ARGUMENTS
  569. CMD_END
  570. X
  571. X
  572. /*************************************************************************/
  573. X   /* declare an old style argument-descriptor array */
  574. static ARGDESC    Args[] =
  575. {
  576. X   STARTOFARGS,
  577. X
  578. X   'n', ARGREQ|ARGPOS, argStr,  __ &Name,  "name (name to look for)",
  579. X   's', ARGVALOPT, argStr,  __ &Str,       "STRing (optional string to use)",
  580. X   'g', ARGVEC,    argStr,  __ &Groups,    "newsGROUPS (newsgroups to test)",
  581. X   'c', ARGOPT,    argInt,  __ &RepCount,  "REPcount (repeat count per group)",
  582. X   'd', ARGOPT,    argStr,   __ &DirName,  "DIRname (work directory)",
  583. X   'i', ARGVEC,    argInt,   __ &Integers, "INTegerS (vector of numbers)",
  584. X   '#', ARGHIDDEN, argBool,  __ &XRated,   "XratedMODE (naughty! naughty!)",
  585. X
  586. X   'x', ARGOPT, argSBool, __ &XFlag, "Xflag (set X flag)",
  587. X   'y', ARGOPT, argUBool, __ &YFlag, "Yflag (unset Y flag)",
  588. X   'z', ARGOPT, argTBool, __ &ZFlag, "Zflag (toggle Z flag)",
  589. X
  590. X   't', ARGOPT,   argChar, __ &TabChar, "TABchar (field delimiter)",
  591. X   'r', ARGNOVAL, argMine, __ NULL,     "raw (trigger raw-mode \
  592. before processing any more arguments on the command-line)",
  593. X
  594. X   ' ', ARGLIST, listStr, __ &Argv, "file (list of files)",
  595. X
  596. X   ENDOFARGS
  597. };
  598. X
  599. X
  600. /***************************************************************************
  601. ** ^FUNCTION: reset_args - reset argument values for another pass
  602. **
  603. ** ^SYNOPSIS:
  604. */
  605. #ifndef __ANSI_C__
  606. X   static VOID reset_args()
  607. #endif
  608. /*  
  609. ** ^PARAMETERS:
  610. **    None.
  611. **
  612. ** ^DESCRIPTION:
  613. **    Reset_args resets all the argument values to their corresponding
  614. **    default values so that we can (re)test the parseargs library.
  615. **
  616. ** ^REQUIREMENTS:
  617. **    None.
  618. **
  619. ** ^SIDE-EFECTS:
  620. **    All the static-global argument variables are rewritten.
  621. **
  622. ** ^RETURN-VALUE:
  623. **    None.
  624. **
  625. ** ^ALGORITHM:
  626. **    Trivial.
  627. ***^^**********************************************************************/
  628. #ifdef __ANSI_C__
  629. X   static void reset_args( void )
  630. #endif
  631. {
  632. X   RepCount = 0;
  633. X   Name     = CHARNULL;
  634. X   Str      = DEF_STR;
  635. X   DirName  = ".";
  636. X   XRated   = FALSE;
  637. X   XFlag    = FALSE;
  638. X   YFlag    = TRUE;
  639. X   ZFlag    = FALSE;
  640. X   TabChar  = ':';
  641. X
  642. X   vecFree(Integers, int);
  643. X   vecDeepFree(Groups, char *);
  644. X   listFree( Argv );
  645. X   Argv = ARGLISTNULL;
  646. }
  647. X
  648. X
  649. /***************************************************************************
  650. ** ^FUNCTION: print_args - print current argument values
  651. **
  652. ** ^SYNOPSIS:
  653. */
  654. #ifndef __ANSI_C__
  655. X   static void print_args( argd )
  656. /*
  657. ** ^PARAMETERS:
  658. */
  659. X   ARGDESC *argd;
  660. /*    -- the command whose arg-values are to be printed
  661. */
  662. #endif  /* !__ANSI_C__ */
  663. X
  664. /* ^DESCRIPTION:
  665. **    Print the current values of all the command-line settings
  666. **
  667. ** ^REQUIREMENTS:
  668. **    The command-line should have already been parsed by one of the
  669. **    Xparseargs functions.
  670. **
  671. ** ^SIDE-EFECTS:
  672. **    Prints on stdout.
  673. **
  674. ** ^RETURN-VALUE:
  675. **    None.
  676. **
  677. ** ^ALGORITHM:
  678. **    Trivial.
  679. ***^^**********************************************************************/
  680. #ifdef __ANSI_C__
  681. X   static void print_args( const ARGDESC *argd )
  682. #endif
  683. {
  684. X   int  i, flags;
  685. X   ArgList *ls;
  686. X
  687. X   printf( "Name = \"%s\", DirName = \"%s\", RepCount = %d,\n",
  688. X           Name, DirName, RepCount );
  689. X
  690. X   printf( "XFlag = %d, YFlag = %d, ZFlag = %d, TabChar='%c'(%03o);\n",
  691. X           XFlag, YFlag, ZFlag, TabChar, TabChar );
  692. X
  693. X   printf( "XRated=%d, Raw-Mode = \"%s\"\n", XRated, Mode );
  694. X
  695. X      /* to call parsecntl() to see if the optional value was supplied */
  696. X   (VOID) parsecntl( (ARGDESC *)argd, pc_ARGFLAGS, pc_READ, "string", &flags);
  697. X
  698. X   if ( BTEST(flags, ARGGIVEN) && !BTEST(flags, ARGVALGIVEN) ) {
  699. X      printf("String=!No Value Given on CmdLine!\n" );
  700. X   }
  701. X   else {
  702. X      printf("String=\"%s\"\n", Str);
  703. X   }
  704. X
  705. X   if (Groups.count) {
  706. X      printf("Newsgroups:");
  707. X      for (i = 0 ; i < Groups.count ; i++ ) {
  708. X         printf(" %s", Groups.array[i]);
  709. X      }
  710. X      putchar('\n');
  711. X   }
  712. X
  713. X   if (Integers.count) {
  714. X      printf("Integers:");
  715. X      for (i = 0 ; i < Integers.count ; i++ ) {
  716. X         printf(" %d", Integers.array[i]);
  717. X      }
  718. X      putchar('\n');
  719. X   }
  720. X
  721. X   if (Argv)  printf("Remaining args: ");
  722. X   for ( ls = Argv ; ls ; L_ADVANCE(ls) ) {
  723. X      printf("%s", L_STRING(ls));
  724. X      if ( L_NEXT(ls) ) {
  725. X         putchar(' ');
  726. X      }
  727. X      else {
  728. X         putchar('\n');
  729. X      }
  730. X   }/*for*/
  731. }
  732. X
  733. X
  734. /*ARGSUSED*/
  735. MAIN(argc, argv)
  736. {
  737. X   parseargs(argv, Cmd);   /* parse the command-line */
  738. X   print_args(Cmd);        /* print what we found */
  739. X
  740. X   putchar('\n');
  741. X   reset_args();           /* reset args for another pass */
  742. X
  743. X   parseargs(argv, Args);  /* parse same command-line using old-style argd */
  744. X   print_args(Args);       /* print what we found (should be same as before) */
  745. X
  746. X   exit(0);  /* wave bye-bye */
  747. }
  748. SHAR_EOF
  749. chmod 0664 parseargs/stest.c ||
  750. echo 'restore of parseargs/stest.c failed'
  751. Wc_c="`wc -c < 'parseargs/stest.c'`"
  752. test 9196 -eq "$Wc_c" ||
  753.     echo 'parseargs/stest.c: original size 9196, current size' "$Wc_c"
  754. rm -f _shar_wnt_.tmp
  755. fi
  756. # ============= parseargs/strfuncs.c ==============
  757. if test -f 'parseargs/strfuncs.c' -a X"$1" != X"-c"; then
  758.     echo 'x - skipping parseargs/strfuncs.c (File already exists)'
  759.     rm -f _shar_wnt_.tmp
  760. else
  761. > _shar_wnt_.tmp
  762. echo 'x - extracting parseargs/strfuncs.c (Text)'
  763. sed 's/^X//' << 'SHAR_EOF' > 'parseargs/strfuncs.c' &&
  764. /**************************************************************************
  765. ** ^FILE: strfuncs.c - Miscellaneous string functions for parseargs
  766. **
  767. ** ^DESCRIPTION:
  768. **    This file implements a wide variety of functions to manipulate
  769. **    strings in way way or another. Some of the functions may already
  770. **    be included in the standard library of some C compilers.
  771. **
  772. **    The following functions are implemented:
  773. **
  774. **       strucpy() -- copy a string and map to uppercase
  775. **       strlcpy() -- copy a string and map to lowercase
  776. **       strupr() -- convert a string to uppercase
  777. **       strlwr() -- convert a string to lowercase
  778. **       strdup() -- return a (newly allocated) copy of a string
  779. **       strpbrk() -- return first occurrence of character in a set
  780. **       strspn() -- return length of initial prefix of a character set
  781. **       strcspn() -- return length of initial prefix of a character set
  782. **       strltrim() -- trim leftmost (leading) characters in a string
  783. **       strrtrim() -- trim rightmost (trailing) characters in a string
  784. **       strtrim() -- trim leading and trailing characters in a string
  785. **       strsplit() -- split a string up into a vector of tokens
  786. **       strjoin() -- join a vector of token into a single string
  787. **       get_name() -- return the aname (argument-name) of an argument
  788. **       get_keyword() -- return the sname (keyword-name) of an argument
  789. **       match() -- match two keywords (case insensitive) upto a unique prefix
  790. **       stricmp() -- case insensitive comparison of strings
  791. **       strnicmp() -- case insensitive length-limited comparison of strings
  792. **       basename() -- remove the leading directories (and disks) from a path
  793. **       indent_para() -- print an indented hanging paragraph
  794. **
  795. ** ^HISTORY:
  796. **    01/02/91     Brad Appleton     <brad@ssd.csd.harris.com>     Created
  797. **    - changed from file misc.c to this name and added all of the strxxx
  798. **      functions (plus got rid of some unused functions).
  799. **
  800. **    --/--/--    Peter da Silva    <peter@ferranti.com>    
  801. **
  802. **    --/--/--    Eric P. Allman    <eric@Berkeley.EDU>     Created
  803. ***^^**********************************************************************/
  804. X
  805. #include <stdio.h>
  806. #include <ctype.h>
  807. #include <useful.h>
  808. X
  809. EXTERN  VOID   syserr  ARGS((const char *, ...));
  810. X
  811. static CONST char WhiteSpace[] = " \t\n\r\v\f";
  812. X
  813. X
  814. #if ( defined(unix_style)  ||  defined(ibm_style) )
  815. # define  TO_KWDCASE(c)  TOLOWER(c)
  816. #else
  817. # define  TO_KWDCASE(c)  TOUPPER(c)
  818. #endif
  819. X
  820. X
  821. /***************************************************************************
  822. ** ^FUNCTION: strucpy, strlcpy - copy dest to src, mapping to upper/lower case
  823. **
  824. ** ^SYNOPSIS:
  825. **
  826. **    char *strucpy( dest, src )
  827. **    char *strlcpy( dest, src )
  828. **
  829. ** ^PARAMETERS:
  830. **    char *dest;
  831. **    -- the address to start copying to
  832. **
  833. **    char *src;
  834. **    -- the address to start copying from
  835. **
  836. ** ^DESCRIPTION:
  837. **    Strlcpy (strucpy) copies src into dest (upto and including the
  838. **    terminating NUL byte) and all uppercase (lowercase) characters in
  839. **    src are mapped to lowercase (uppercase) before being copied into dest.
  840. **
  841. ** ^REQUIREMENTS:
  842. **    Dest must be non-null, and large enough to hold the copied result.
  843. **
  844. ** ^SIDE-EFECTS:
  845. **    Dest is (re)written
  846. **
  847. ** ^RETURN-VALUE:
  848. **    Address of dest.
  849. **
  850. ** ^ALGORITHM:
  851. **    Trivial.
  852. ***^^**********************************************************************/
  853. #ifdef __ANSI_C__
  854. X   char *strucpy( char *dest, const char *src )
  855. #else
  856. X   char *strucpy( dest, src )  char *dest, *src;
  857. #endif
  858. {
  859. X   register char  *s1 = dest;
  860. X   register CONST char  *s2 = src;
  861. X
  862. X   if ( !s2 )  return  CHARNULL;
  863. X
  864. X   for ( ; *s2 ; s1++, s2++ ) {
  865. X      *s1 = TOUPPER( *s2 );
  866. X   }
  867. X   *s1 = '\0';
  868. X
  869. X   return   s1;
  870. }
  871. X
  872. X
  873. #ifdef __ANSI_C__
  874. X   char *strlcpy( char *dest, const char *src )
  875. #else
  876. X   char *strlcpy( dest, src )  char *dest, *src;
  877. #endif
  878. {
  879. X   register char  *s1 = dest;
  880. X   register CONST char  *s2 = src;
  881. X
  882. X   if ( !s2 )  return  CHARNULL;
  883. X
  884. X   for ( ; *s2 ; s1++, s2++ ) {
  885. X      *s1 = TOLOWER( *s2 );
  886. X   }
  887. X   *s1 = '\0';
  888. X
  889. X   return   s1;
  890. }
  891. X
  892. X
  893. /***************************************************************************
  894. ** ^FUNCTION: strupr, strlwr - convert a string to all upper/lower case
  895. **
  896. ** ^SYNOPSIS:
  897. **    char *strupr( str )
  898. **    char *strlwr( str )
  899. **
  900. ** ^PARAMETERS:
  901. **    char *str;
  902. **    -- the string to be converted
  903. **
  904. ** ^DESCRIPTION:
  905. **    Strupr (strlwr) converts all lowercase (uppercase) characters in <str>
  906. **    to uppercase (lowercase) and returns the address of <str>.
  907. **
  908. ** ^REQUIREMENTS:
  909. **    str should be non-null and non-empty.
  910. **
  911. ** ^SIDE-EFECTS:
  912. **    str is overwritten with the uppercase (lowercase) result.
  913. **
  914. ** ^RETURN-VALUE:
  915. **    Address of str.
  916. **
  917. ** ^ALGORITHM:
  918. **    Trivial.
  919. ***^^**********************************************************************/
  920. #ifdef __ANSI_C__
  921. X   char *strupr( char *str )
  922. #else
  923. X   char *strupr( str )  char *str;
  924. #endif
  925. {
  926. X   char *p = str;
  927. X
  928. X   for ( ; p && *p ; p++ ) {
  929. X      if ( islower(*p) )  *p = toupper(*p);
  930. X   }
  931. X
  932. X   return   str;
  933. }
  934. X
  935. X
  936. #ifdef __ANSI_C__
  937. X   char *strlwr( char *str )
  938. #else
  939. X   char *strlwr( str )  char *str;
  940. #endif
  941. {
  942. X   char *p = str;
  943. X
  944. X   for ( ; p && *p ; p++ ) {
  945. X      if ( isupper(*p) )  *p = tolower(*p);
  946. X   }
  947. X
  948. X   return   str;
  949. }
  950. X
  951. X
  952. /***************************************************************************
  953. ** ^FUNCTION: stricmp, strnicmp - case insensitive string comparison
  954. **
  955. ** ^SYNOPSIS:
  956. **    int stricmp( s1, s2 )
  957. **    int strnicmp( s1, s2, n )
  958. **
  959. ** ^PARAMETERS:
  960. **    char *s1;
  961. **    -- first string to compare
  962. **
  963. **    char *s2;
  964. **    -- second string to compare
  965. **
  966. **    size_t  n;
  967. **    -- The number of characters to compare
  968. **
  969. ** ^DESCRIPTION:
  970. **    Stricmp (strnicmp) is identical to strcmp (strncmp) except that it
  971. **    it performs a case-insensitive comparison of characters.
  972. **
  973. ** ^REQUIREMENTS:
  974. **    Both s1 and s2 should be non-null and non-empty
  975. **
  976. ** ^SIDE-EFECTS:
  977. **    None.
  978. **
  979. ** ^RETURN-VALUE:
  980. **    < 0    if s1 < s2
  981. **    = 0    if s1 matches s2
  982. **    > 0    if s1 > s2
  983. **
  984. ** ^ALGORITHM:
  985. **    Trivial.
  986. ***^^**********************************************************************/
  987. #ifdef __ANSI_C__
  988. X   int stricmp( const char *str1, const char *str2 )
  989. #else
  990. X   int stricmp( str1, str2 ) char *str1, *str2;
  991. #endif
  992. {
  993. X   register  CONST char *s1 = str1, *s2 = str2;
  994. X   register  char  c1, c2;
  995. X
  996. X   if ( s1 == s2 )  return   0;
  997. X   if ( !s1 )       return  -1;
  998. X   if ( !s2 )       return   1;
  999. X
  1000. X   for ( ; *s1 && *s2 ; s1++ , s2++ ) {
  1001. X      c1 = TOLOWER( *s1 );
  1002. X      c2 = TOLOWER( *s2 );
  1003. X
  1004. X      if (c1 != c2)  return  (int)(c1 -c2);
  1005. X   }
  1006. X   return   (*s1 == *s2) ? 0 : (int)(*s1 - *s2);
  1007. }
  1008. X
  1009. X
  1010. #ifdef __ANSI_C__
  1011. X   int strnicmp( const char *str1, const char *str2, size_t len )
  1012. #else
  1013. X   int strnicmp( str1, str2, len ) char *str1, *str2; size_t  len;
  1014. #endif
  1015. {
  1016. X   register  CONST char *s1 = str1, *s2 = str2;
  1017. X   register  char  c1, c2;
  1018. X
  1019. X   if ( s1 == s2 )  return   0;
  1020. X   if ( !s1 )       return  -1;
  1021. X   if ( !s2 )       return   1;
  1022. X
  1023. X   for ( ; *s1 && *s2 && len ; s1++ , s2++ , len-- ) {
  1024. X      c1 = TOLOWER( *s1 );
  1025. X      c2 = TOLOWER( *s2 );
  1026. X
  1027. X      if (c1 != c2)  return  (int)(c1 -c2);
  1028. X   }
  1029. X   return   (*s1 == *s2) ? 0 : (int)(*s1 - *s2);
  1030. }
  1031. X
  1032. X
  1033. #ifdef BSD
  1034. X
  1035. /***************************************************************************
  1036. ** ^FUNCTION: strdup - copy a string
  1037. **
  1038. ** ^SYNOPSIS:
  1039. */
  1040. # ifndef __ANSI_C__
  1041. X   char *strdup( str )
  1042. /*
  1043. ** ^PARAMETERS:
  1044. */
  1045. X   char *str;
  1046. /*    -- the string to replicate
  1047. */
  1048. # endif  /* !__ANSI_C__ */
  1049. X
  1050. /* ^DESCRIPTION:
  1051. **    Strdup allocates storrage and copies the given string into the
  1052. **    newly acquired space (returning its address). The returned result
  1053. **    should be deallocated using free().
  1054. **
  1055. ** ^REQUIREMENTS:
  1056. **    str should be non-null
  1057. **
  1058. ** ^SIDE-EFFECTS:
  1059. **    None.
  1060. **
  1061. ** ^RETURN-VALUE:
  1062. **    Address of the newly allocated string.
  1063. **
  1064. ** ^ALGORITHM:
  1065. **    Trivial.
  1066. ***^^**********************************************************************/
  1067. # ifdef __ANSI_C__
  1068. X   char *strdup( const char *str )
  1069. # endif
  1070. {
  1071. X  unsigned len = strlen(str) + 1;
  1072. X  char *p = malloc( len * sizeof(char) );
  1073. X
  1074. X  if ( !p )  syserr( "Fatal Error -- out of memory" );
  1075. X  strcpy(p, str);
  1076. X
  1077. X  return p;
  1078. }
  1079. X
  1080. X
  1081. /***************************************************************************
  1082. ** ^FUNCTION: strpbrk - return the first occurrence of characters in a string
  1083. **
  1084. ** ^SYNOPSIS:
  1085. */
  1086. #ifndef __ANSI_C__
  1087. X   char *strpbrk( str1, str2 )
  1088. /*
  1089. ** ^PARAMETERS:
  1090. */
  1091. X   char *str1;
  1092. /*    -- the string to be searched
  1093. */
  1094. X   char *str2;
  1095. /*    -- the set of characters to be located
  1096. */
  1097. #endif  /* !__ANSI_C__ */
  1098. X
  1099. /* ^DESCRIPTION:
  1100. **    Strpbrk will attempt to locate the first occurence in str1 of any 
  1101. **    character from str2 and return the address of the first such
  1102. **    occurrence. If str1 contains NO characters from str2, then NULL
  1103. **    is returned.
  1104. **
  1105. ** ^REQUIREMENTS:
  1106. **    Both str1 and str2 should be non-null and non-empty
  1107. **
  1108. ** ^SIDE-EFECTS:
  1109. **    None.
  1110. **
  1111. ** ^RETURN-VALUE:
  1112. **    A pointer to the first occurence in str1 of any char from str2.
  1113. **
  1114. ** ^ALGORITHM:
  1115. **    - foreach char in str1
  1116. **       - if char is in str2, return the address of char
  1117. **      end-for
  1118. **    - if we have reached the end of str1, return NULL
  1119. ***^^**********************************************************************/
  1120. #ifdef __ANSI_C__
  1121. X   char *strpbrk( const char *str1, const char *str2 )
  1122. #endif
  1123. {
  1124. X   register CONST char *s1 =  str1, *s2 = str2;
  1125. X
  1126. X   if ( !s1 || !*s1 || !s2 || !*s2 )  return  CHARNULL;
  1127. X
  1128. X   for ( ; *s1 ; s1++ )  {
  1129. X      if ( strchr(s2, *s1) )  return (char *)s1;
  1130. X   }
  1131. X
  1132. X   return  CHARNULL;
  1133. }
  1134. X
  1135. X
  1136. /***************************************************************************
  1137. ** ^FUNCTION: strspn, strcspn - identify leading runs of characters
  1138. **
  1139. ** ^SYNOPSIS:
  1140. **    char *strspn( str1, str2 )
  1141. **    char *strcspn( str1, str2 )
  1142. **
  1143. ** ^PARAMETERS:
  1144. **    char *str1;
  1145. **    -- the string to be searched
  1146. **
  1147. **    char *str2;
  1148. **    -- the string to be searched
  1149. **
  1150. ** ^DESCRIPTION:
  1151. **    Strspn (strcspn) attempts to determine the length of the longest
  1152. **    leading prefix of str1 that consists entirely of character from
  1153. **    (not from) str2.
  1154. **
  1155. ** ^REQUIREMENTS:
  1156. **    Both str1 and str2 should be non-null and non-empty.
  1157. **
  1158. ** ^SIDE-EFECTS:
  1159. **    None.
  1160. **
  1161. ** ^RETURN-VALUE:
  1162. **    The length of the initial prefix in str1 consisting entirely
  1163. **    of characters from (not from) str2.
  1164. **
  1165. ** ^ALGORITHM:
  1166. **    - length = 0
  1167. **    - for each char in str1
  1168. **       - if char is in str2 (for strcspn) or not in str2 (for strcspn)
  1169. **            then return length
  1170. **       - else
  1171. **            add 1 to length
  1172. **         end-if
  1173. **      end-for
  1174. **    - if end-of-string then return length
  1175. **
  1176. ***^^**********************************************************************/
  1177. #ifdef __ANSI_C__
  1178. X   int strspn( const char *str1, const char *str2 )
  1179. #else
  1180. X   int strspn( str1, str2 )  char *str1, *str2;
  1181. #endif
  1182. {
  1183. X   register CONST char  *s1 = str1, *s2 = str2;
  1184. X   int len = 0;
  1185. X
  1186. X   if ( !s1 || !*s1 || !s2 || !*s2 )  return  0;
  1187. X   while ( *s1  &&  strchr(s2, *s1++) )  ++len;
  1188. X   return  len;
  1189. }
  1190. X
  1191. X
  1192. #ifdef __ANSI_C__
  1193. X   int strcspn( const char *str1, const char *str2 )
  1194. #else
  1195. X   int strcspn( str1, str2 )  char *str1, *str2;
  1196. #endif
  1197. {
  1198. X   register CONST char  *s1 = str1, *s2 = str2;
  1199. X   int len = 0;
  1200. X
  1201. X   if ( !s1 || !*s1 || !s2 || !*s2 )  return  0;
  1202. X   while ( *s1  &&  !strchr(s2, *s1++) )  ++len;
  1203. X   return  len;
  1204. }
  1205. X
  1206. #endif  /* BSD */
  1207. X
  1208. X
  1209. /***************************************************************************
  1210. ** ^FUNCTION: strltrim, strrtrim, strtrim - trim leading/trailing characters
  1211. **
  1212. ** ^SYNOPSIS:
  1213. **    char *strltrim( str, charset )
  1214. **    char *strrtrim( str, charset )
  1215. **    char *strtrim( str, charset )
  1216. **
  1217. ** ^PARAMETERS:
  1218. **    char *str;
  1219. **    -- the string to be trimmed
  1220. **
  1221. **    char *charset;
  1222. **    -- the set of characters to be trimmed
  1223. **
  1224. ** ^DESCRIPTION:
  1225. **    Strltrim removes from str, all leftmost (leading) characters occurring
  1226. **    in charset.
  1227. **
  1228. **    Strrtrim removes from str, all rightmost (trailing) characters occurring
  1229. **    in charset.
  1230. **
  1231. **    Strtrim removes from str, all leading and trailing characters occurring
  1232. **    in charset.
  1233. **
  1234. **    For each of these functions, if charset is NULL or empty, then the set
  1235. **    of whitespace characters (space, tab, newline, carriage-return, form-feed
  1236. **    and vertical-tab) is assumed.
  1237. **
  1238. ** ^REQUIREMENTS:
  1239. **    str should be non-null and non-empty.
  1240. **
  1241. ** ^SIDE-EFECTS:
  1242. **    characters may be removed from the beginning and/or end of str.
  1243. **
  1244. ** ^RETURN-VALUE:
  1245. **    Address of str.
  1246. **
  1247. ** ^ALGORITHM:
  1248. **    Trivial.
  1249. ***^^**********************************************************************/
  1250. #ifdef __ANSI_C__
  1251. X   char *strltrim( char *str, const char *charset )
  1252. #else
  1253. X   char *strltrim( str, charset )  char *str, *charset;
  1254. #endif
  1255. {
  1256. X   register   int   i;
  1257. X
  1258. X   if ( !str  ||  !*str )   return   str;
  1259. X      /* if delim-string is NULL, whitespace is used */
  1260. X   if ( !charset )   charset = WhiteSpace;
  1261. X
  1262. X   i = strspn( str, charset );
  1263. X   if ( i > 0 )  strcpy( str, &(str[i]) );
  1264. X
  1265. X   return   str;
  1266. }
  1267. X
  1268. X
  1269. #ifdef __ANSI_C__
  1270. X   char *strrtrim( char *str, const char *charset )
  1271. #else
  1272. X   char *strrtrim( str, charset )  char *str, *charset;
  1273. #endif
  1274. {
  1275. X   register   int   i;
  1276. X
  1277. X   if ( !str  ||  !*str )   return   str;
  1278. X   if ( !charset )   charset = WhiteSpace;
  1279. X   for ( i = strlen(str) - 1 ;
  1280. X            ( i >= 0 ) && (strchr( charset, str[i] )) ;
  1281. X            i--
  1282. X         ) ;
  1283. X
  1284. X   str[i+1] = '\0';
  1285. X
  1286. X   return   str;
  1287. }
  1288. X
  1289. X
  1290. #ifdef __ANSI_C__
  1291. X   char *strtrim( char *str, const char *charset )
  1292. #else
  1293. X   char *strtrim( str, charset )  char *str, *charset;
  1294. #endif
  1295. {
  1296. X   register   int   i;
  1297. X
  1298. X   if ( !str  ||  !*str )   return   str;
  1299. X   if ( !charset )   charset = WhiteSpace;
  1300. X   i = strspn( str, charset );
  1301. X   if ( i > 0 )  strcpy( str, &(str[i]) );
  1302. X
  1303. X   for ( i = strlen(str) - 1 ;
  1304. X            ( i >= 0 ) && (strchr( charset, str[i] )) ;
  1305. X            i--
  1306. X         ) ;
  1307. X
  1308. X   str[i+1] = '\0';
  1309. X
  1310. X   return   str;
  1311. }
  1312. X
  1313. X
  1314. /***************************************************************************
  1315. ** ^FUNCTION: strsplit - split a string into tokens
  1316. **
  1317. ** ^SYNOPSIS:
  1318. */
  1319. #ifndef __ANSI_C__
  1320. X   int  strsplit( vec, token_str, separators )
  1321. /*
  1322. ** ^PARAMETERS:
  1323. */
  1324. X   char **vec[];
  1325. /*    -- pointer to the string vector to be allocated
  1326. */
  1327. X   char token_str[];
  1328. /*    -- the string to be split up
  1329. */
  1330. X   char separators[];
  1331. /*    -- the delimiters that separate tokens
  1332. */
  1333. #endif  /* !__ANSI_C__ */
  1334. X
  1335. /* ^DESCRIPTION:
  1336. **    Strsplit will split token_str up into  a vector of tokens that are
  1337. **    separated by one or more characters from <separators>. The number
  1338. **    of tokens found is returned and storage is allocated for the given
  1339. **    vector (which may later be deallocated using free()).
  1340. **
  1341. **    If <separators> is NULL or empty, then the set of whitespace characters
  1342. **    is used as the token delimiters.
  1343. **
  1344. ** ^REQUIREMENTS:
  1345. **    vec must be non-NULL (it must be a valid address).
  1346. **    token_str should be non-null and non-empty
  1347. **
  1348. ** ^SIDE-EFECTS:
  1349. **    All leading and trailing characters from <separators> are removed
  1350. **    from token_str. Furthermore, all remaining sequences in token_str
  1351. **    of characters from <separators> are replaced with a single NUL-byte.
  1352. **
  1353. **    Token_str holds the actual storage for all the strings in the newly
  1354. **    created vector.
  1355. **
  1356. ** ^RETURN-VALUE:
  1357. **    The number of tokens parsed.
  1358. **
  1359. ** ^ALGORITHM:
  1360. **    - count the number of tokens present while at the same time removing
  1361. **      all leading and trailing delimiters, and replacing all other sequences
  1362. **      of delimiters with the NUL character.
  1363. **    - allocate a vector large enough to point to all the token strings.
  1364. **    - for i in 0 .. (numtokens - 1) do
  1365. **         - vector[i] = token_str
  1366. **         - advance token_str to point at the next character past the
  1367. **           righmost NUL-byte (which should be the start of the next token).
  1368. **      end-for
  1369. **    - return the number of tokens parsed.
  1370. ***^^**********************************************************************/
  1371. #ifdef __ANSI_C__
  1372. X   int strsplit( char **vec[], char token_str[], const char separators[] )
  1373. #endif
  1374. {
  1375. X   register   char c, *pread, *pwrite;
  1376. X   int   i, count = 0;
  1377. X
  1378. X   if ( !token_str )    return   0;
  1379. X      /* if delim-string is NULL, whitespace is used */
  1380. X   if ( !separators )   separators = WhiteSpace;
  1381. X
  1382. X      /* trim leading separators */
  1383. X   pread = token_str;
  1384. X   while ( strchr(separators, *pread) )   ++pread;
  1385. X   token_str = pwrite = pread;
  1386. X
  1387. X      /*
  1388. X      ** make first pass through string, counting # of tokens and
  1389. X      ** separating all tokens by a single '\0'
  1390. X      */
  1391. X   while ( c = *pread++ ) {
  1392. X      if ( !strchr(separators, c) )   {
  1393. X         *pwrite++ = c;
  1394. X      }
  1395. X      else {
  1396. X         *pwrite++ = '\0';   /* null terminate this token */
  1397. X         ++count;                /* update token count */
  1398. X         while ( strchr(separators, *pread) )   ++pread;
  1399. X      }
  1400. X   }/*while*/
  1401. X   if ( *(pwrite - 1) )  {
  1402. X      ++count;         /* dont forget last token */
  1403. X      *pwrite = '\0';   /* null-terminate */
  1404. X   }
  1405. X
  1406. X      /* allocate space for the caller's vector (remember NULL at the end) */
  1407. X   (*vec) = (char **)malloc( (1 + count) * sizeof( char * ) );
  1408. X   if ( !*vec ) {
  1409. X      fprintf( stderr, "out of memory in strsplit() - aborting\n" );
  1410. X      exit( -1 );
  1411. X   }
  1412. X
  1413. X      /* now go thru token-string again assigning pointers from vector */
  1414. X   pread = token_str;
  1415. X   for ( i = 0 ; i < count ; i++ ) {
  1416. X      (*vec)[i] = pread;   /* assign pointer */
  1417. X      pread += strlen( pread ) + 1;
  1418. X   }/* end-for */
  1419. X
  1420. X      /* set up the trailing pointer to NULL at the end */
  1421. X   (*vec)[ count ] = CHARNULL;
  1422. X   return   count;
  1423. }
  1424. X
  1425. X
  1426. /***************************************************************************
  1427. ** ^FUNCTION: strjoin - join a vector of tokens together
  1428. **
  1429. ** ^SYNOPSIS:
  1430. */
  1431. #ifndef __ANSI_C__
  1432. X   char  *strjoin( argv, separator )
  1433. /*
  1434. ** ^PARAMETERS:
  1435. */
  1436. X   char *argv[];
  1437. /*    -- pointer to the string vector to join together
  1438. */
  1439. X   char separator[];
  1440. /*    -- the the string to use to separate tokens (if NULL, " " is used)
  1441. */
  1442. #endif  /* !__ANSI_C__ */
  1443. X
  1444. /* ^DESCRIPTION:
  1445. **    Strjoin will make a single string out of the given vector by copying
  1446. **    all the tokens from the given vector (in order) toa newly allocated
  1447. **    string. Each token will be separated by an occurence of <separator>.
  1448. **
  1449. **    If <separator> is NULL then a single space is used as the separator.
  1450. **    If <separator> is empty, then no separator is used and the tokens are
  1451. **    simply concatenated together.
  1452. **
  1453. ** ^REQUIREMENTS:
  1454. **    argv must be non-NULL (it must be a valid address), and must be terminated
  1455. **    by a pointer to NULL (argv[last+1] == NULL).
  1456. **
  1457. ** ^SIDE-EFECTS:
  1458. **    Storage is allocated.
  1459. **
  1460. ** ^RETURN-VALUE:
  1461. **    The addres of the newly-joined results (which should be deallocated
  1462. **    using free()). Returns NULL if nothing was joined.
  1463. **
  1464. ** ^ALGORITHM:
  1465. **    - count the number of characters to place in the joined-result.
  1466. **    - allocate a string large-enough to copy the joined-result into.
  1467. **    - copy each string into the string (with <separator> between tokens).
  1468. **    - 0 return the result.
  1469. ***^^**********************************************************************/
  1470. #ifdef __ANSI_C__
  1471. X   char *strjoin( const char *argv[], const char separator[] )
  1472. #endif
  1473. {
  1474. X   size_t  sz = 0;
  1475. X   register char *p;
  1476. X   register CONST char *a, **av;
  1477. X   register int  seplen;
  1478. X   char *result;
  1479. X
  1480. X      /* if argv is NULL, nothing to do */
  1481. X   if ( !argv )  return  CHARNULL;
  1482. X   if ( !separator )  separator = " ";
  1483. X   seplen = strlen( separator );
  1484. X
  1485. X      /* figure out how much space we need */
  1486. X   for ( av = argv ; *av ; av++ ) {
  1487. X      if ( !**av )  continue;
  1488. X      sz += strlen( *av );
  1489. X      if ( seplen  &&  *(av + 1) )  sz += seplen;
  1490. X   }
  1491. X
  1492. X      /* allocate space */
  1493. X   result = (char *)malloc( (sz + 1) * sizeof(char) );
  1494. X   if ( !result )  syserr( "malloc failed in strjoin()" );
  1495. X
  1496. X      /* join the strings together */
  1497. X   *result = '\0';
  1498. X   for ( av = argv, p = result ; (a = *av) ; av++ ) {
  1499. X      if ( !*a )  continue;
  1500. X      while ( (*p = *a++) ) ++p;  /* copy token */
  1501. X      if ( seplen  &&  *(av + 1) ) {
  1502. X         a = separator;
  1503. X         while ( (*p = *a++) ) ++p;  /* copy separator */
  1504. X      }/*end-if*/
  1505. X   }/*end-for*/
  1506. X
  1507. X   return  result;
  1508. }
  1509. X
  1510. X
  1511. /***************************************************************************
  1512. ** ^FUNCTION: get_name - return the aname (argument-name) of an argument
  1513. **
  1514. ** ^SYNOPSIS:
  1515. */
  1516. #ifndef __ANSI_C__
  1517. X   char  *get_name( s, buf )
  1518. /*
  1519. ** ^PARAMETERS:
  1520. */
  1521. X   char *s;
  1522. /*    -- the ad_prompt field of an ARGDESC struct
  1523. */
  1524. X   char *buf;
  1525. /*    -- address to which the aname should be copied
  1526. */
  1527. #endif  /* !__ANSI_C__ */
  1528. X
  1529. /* ^DESCRIPTION:
  1530. **    Get_name will get the full argument name of the given argument
  1531. **    (not just the keyword name) and copy it to buf.
  1532. **
  1533. ** ^REQUIREMENTS:
  1534. **    Both s and buf must be non-null and non-empty.
  1535. **    buf must be large enough to hold the result.
  1536. **
  1537. ** ^SIDE-EFECTS:
  1538. **    buf is overwritten.
  1539. **
  1540. ** ^RETURN-VALUE:
  1541. **    Address of the buffer containing the name.
  1542. **
  1543. ** ^ALGORITHM:
  1544. **    determine the name of an argument from its prompt
  1545. **    and copy the result in the given buffer
  1546. ***^^**********************************************************************/
  1547. #ifdef __ANSI_C__
  1548. X   char *get_name( const char *s, char *buf )
  1549. #endif
  1550. {
  1551. X      /* <buf> must be large enough to hold the result! */
  1552. X   strlcpy(buf, s);
  1553. X   return   buf;
  1554. }
  1555. X
  1556. X
  1557. /***************************************************************************
  1558. ** ^FUNCTION: get_keyword - get the sname (keyword name) of an argument
  1559. **
  1560. ** ^SYNOPSIS:
  1561. */
  1562. #ifndef __ANSI_C__
  1563. X   char  *get_keyword( s, buf )
  1564. /*
  1565. ** ^PARAMETERS:
  1566. */
  1567. X   char *s;
  1568. /*    -- the ad_prompt field of an ARGDESC struct
  1569. */
  1570. X   char *buf;
  1571. /*    -- address to which the sname should be copied
  1572. */
  1573. #endif  /* !__ANSI_C__ */
  1574. X
  1575. /* ^DESCRIPTION:
  1576. **    Get_name will get the keyword name of the given argument
  1577. **    (not the entire argument name) and copy it to buf.
  1578. **
  1579. **    The sname (keyword-name) consists only of all uppercase characters
  1580. **    from the ad_prompt field (in the order they occur). If the ad_prompt
  1581. **    field contains NO uppercase characters, than the aname and the sname
  1582. **    are equivalent (the entire string).
  1583. **
  1584. ** ^REQUIREMENTS:
  1585. **    Both s and buf must be non-null and non-empty.
  1586. **    buf must be large enough to hold the result.
  1587. **
  1588. ** ^SIDE-EFECTS:
  1589. **    buf is overwritten.
  1590. *
  1591. ** ^RETURN-VALUE:
  1592. **    Address of the buffer containing the keyword.
  1593. **
  1594. ** ^ALGORITHM:
  1595. **    determine the keyword of an argument from its prompt
  1596. **    and copy the result in the given buffer
  1597. ***^^**********************************************************************/
  1598. #ifdef __ANSI_C__
  1599. X   char *get_keyword( const char *s, char *buf )
  1600. #endif
  1601. {
  1602. X   register char *p1 = (char *)s, *p2;
  1603. X   register int   i, len = 0;
  1604. X   char *caps = CHARNULL;
  1605. X
  1606. X   if ( !p1 )  return  CHARNULL;
  1607. X
  1608. X      /* find size to copy (use all caps if possible) */
  1609. X   for ( p1 = (char *)s ; *p1 ; p1++ )   {
  1610. X     if ( !caps  &&  isupper( *p1 ) )  caps = p1;
  1611. X         if ( caps   &&   isupper( *p1 ) )   ++len;
  1612. X   }
  1613. X   if ( !caps )   len = (int) (p1 - (char *)s);
  1614. X
  1615. X      /* copy string into buffer and convert it to desired case */
  1616. X      /* <buf> must be large enough to hold the result! */
  1617. X   p1 = buf;
  1618. X   if ( len )   {
  1619. X     if ( !caps ) {
  1620. X        for ( p1 = buf, p2 = (char *)s, i = 0 ; i < len ; p1++, p2++, i++ ) {
  1621. X            *p1 = TO_KWDCASE(*p2);
  1622. X        }
  1623. X     }/*if*/
  1624. X
  1625. X     else {
  1626. X        for ( p2 = caps, i = 0 ; i < len ; p2++ ) {
  1627. X           if ( isupper( *p2 ) )   {
  1628. X              *(p1++) = TO_KWDCASE(*p2);
  1629. X              ++i;
  1630. X           }
  1631. X        }/*for*/
  1632. X     }/*else*/
  1633. X   }/*if*/
  1634. X   *p1 = '\0';
  1635. X
  1636. X   return   buf;   /* return buffer address */
  1637. }
  1638. #ifndef amiga_style
  1639. X
  1640. /***************************************************************************
  1641. ** ^FUNCTION: match - match a keyword against a prospective argument
  1642. **
  1643. ** ^SYNOPSIS:
  1644. */
  1645. #ifndef __ANSI_C__
  1646. X   int match( candidate, target )
  1647. /*
  1648. ** ^PARAMETERS:
  1649. */
  1650. X   char *candidate;
  1651. /*    -- the possible keyword argument
  1652. */
  1653. X   char *target;
  1654. /*    -- the keyword to be matched
  1655. */
  1656. #endif  /* !__ANSI_C__ */
  1657. X
  1658. /* ^DESCRIPTION:
  1659. **    Match will attempt to see if the candidate string matches the
  1660. **    target string (case insensitive). First a match is tried on the
  1661. **    sname of the keyword, then on the aname.  Candidate may be only
  1662. **    a partial leading portion of the target as long as it is at least
  1663. **    two characters long (unless the keyword is 1 character long).
  1664. **
  1665. **    No "partial" matching is accepted for AmigaDOS command-lines.
  1666. **
  1667. ** ^REQUIREMENTS:
  1668. **    Both candidate and target should be non-null and non-empty.
  1669. **    target should be the ad_prompt field of an ARGDESC structure.
  1670. **
  1671. ** ^SIDE-EFECTS:
  1672. **    None.
  1673. **
  1674. ** ^RETURN-VALUE:
  1675. *     < 0  if candidate < target
  1676. **    = 0  if candidate matches target
  1677. **    > 0  if candidate > target
  1678. **
  1679. ** ^ALGORITHM:
  1680. **    - attempt a partial match against the sname and return 0 if we succeed
  1681. **    - attempt a partial match against the aname and return 0 if we succeed
  1682. **    - if both the above fail return non-zero (no match).
  1683. **    
  1684. ***^^**********************************************************************/
  1685. X
  1686. /* rewritten 8/20/90 --BDA */
  1687. #define MINLEN  2     /* minimum # of characters to match */
  1688. X
  1689. #ifdef __ANSI_C__
  1690. X   int match ( const char *candidate, const char *target )
  1691. #endif
  1692. {
  1693. X   int  i, clen, tlen, too_short=0;
  1694. X   CONST char *full_targ;
  1695. X   char *up_targ;
  1696. X
  1697. X
  1698. X   full_targ = target;
  1699. X
  1700. X      /* make up_targ the uppercase portion of target */
  1701. X   up_targ = strdup( full_targ );
  1702. X   (VOID) get_keyword( full_targ, up_targ );
  1703. X
  1704. X      /* match at least MINLEN characters if possible */
  1705. X   tlen = strlen( up_targ );
  1706. X   clen = strlen( candidate );
  1707. X   if ( (tlen >= MINLEN)   &&   (clen < MINLEN) ) {
  1708. X      ++too_short;      /* not long enough -- no match */
  1709. X   }
  1710. X
  1711. #ifdef vms_style
  1712. X      /* if first two chars are NO then match at least MINLEN+2 chars */
  1713. X   if ( !strnicmp(up_targ, "NO", 2) ) {
  1714. X      if ( (tlen >= (MINLEN + 2))   &&   (clen < (MINLEN + 2)) ) {
  1715. X         ++too_short;      /* not long enough -- no match */
  1716. X      }
  1717. X   }
  1718. #endif
  1719. X
  1720. X      /* first try to match prefix of the uppercase portion */
  1721. X   i = (too_short) ? -1 : strnicmp(up_targ, candidate, clen);
  1722. X
  1723. X   free( up_targ );
  1724. X
  1725. X      /* did we match? */
  1726. X   if ( !i )  return  0;   /* yes! */
  1727. X
  1728. X   /* no! : compare the whole target
  1729. X   **       match at least MINLEN characters if possible
  1730. X   */
  1731. X   tlen = strlen(full_targ);
  1732. X   if ( (tlen >= MINLEN)   &&   (clen < MINLEN) ) {
  1733. X      return   -1;      /* not long enough -- no match */
  1734. X   }
  1735. X
  1736. #ifdef vms_style
  1737. X   /* if first two chars are NO then match at least MINLEN+2 chars */
  1738. X   if ( !strnicmp(full_targ, "no", 2) ) {
  1739. X      if ( (tlen >= (MINLEN + 2))   &&   (clen < (MINLEN + 2)) ) {
  1740. X         return   -1;      /* not long enough -- no match */
  1741. X      }
  1742. X   }
  1743. #endif
  1744. X
  1745. X   return   strnicmp(full_targ, candidate, clen);
  1746. }
  1747. X
  1748. X
  1749. /* here is the AmigaDOS version of match() */
  1750. #else
  1751. X
  1752. # ifdef __ANSI_C__
  1753. X   int match( const char *candidate, const char *target )
  1754. # else
  1755. X   int match( candidate, target) char *candidate, *target;
  1756. # endif
  1757. {
  1758. X   int i, j;
  1759. X   char c;
  1760. X
  1761. X   i = j = 0;
  1762. X
  1763. X   while ( isgraph(target[i]) || isgraph(candidate[i]) ) {
  1764. X      while ( islower(target[i]) ) i++;
  1765. X      if ( !isgraph(target[i]) ) {
  1766. X         if ( !isgraph(candidate[j]) )  return 0;
  1767. X         return  stricmp(target, candidate);
  1768. X      }
  1769. X      c = islower( candidate[j] ) ? toupper(candidate[j]) : candidate[j];
  1770. X      if (target[i] != c)  return  stricmp(target, candidate);
  1771. X      i++;
  1772. X      j++;
  1773. X   }
  1774. X   return 0;
  1775. }
  1776. X
  1777. #endif
  1778. X
  1779. X
  1780. /***************************************************************************
  1781. ** ^FUNCTION: basename - return the last component of a pathname
  1782. **
  1783. ** ^SYNOPSIS:
  1784. **    char *basename( path )
  1785. **
  1786. ** ^PARAMETERS:
  1787. **    path;
  1788. **    -- the pathname to be truncated.
  1789. **
  1790. ** ^DESCRIPTION:
  1791. **    Basename takes a pathname and strips of all leading components
  1792. **    (except for the very last one) which refer to directories or
  1793. **    disk-drives.
  1794. **
  1795. ** ^REQUIREMENTS:
  1796. **    path should be non-null, non-empty, and should correspond to a valid
  1797. **    pathname (absolute or relative).
  1798. **
  1799. ** ^SIDE-EFECTS:
  1800. **    None under Unix and AmigaDOS.
  1801. **
  1802. **    Under VMS, the file version is removed and any .COM or .EXE extension
  1803. **    is also removed.
  1804. **
  1805. **    Under MS-DOS, any .EXE, .COM, or .BAT extension is removed.
  1806. **
  1807. **    Under OS/2, any .EXE, .COM, or .CMD extension is removed.
  1808. **    
  1809. ** ^RETURN-VALUE:
  1810. **    The address of the basename of the path.
  1811. **
  1812. ** ^ALGORITHM:
  1813. **    Trivial.
  1814. ***^^**********************************************************************/
  1815. X   /* should use '\\' for MS-DOS & OS/2 and use ']' for VMS */
  1816. #ifdef vms
  1817. #define PATH_SEP ']'
  1818. X
  1819. X      /* VAX/VMS version of basename */
  1820. # ifdef __ANSI_C__
  1821. X   char *basename( char  path[] )
  1822. # else
  1823. X   char *basename( path ) char  path[];
  1824. # endif
  1825. X   {
  1826. X      char *base = strrchr( path, PATH_SEP );
  1827. X      char *vers = strrchr( path, ';' );
  1828. X      char *ext  = strrchr( path, '.' );
  1829. X
  1830. X      if ( !base ) {
  1831. X         if ( !(base = strrchr( path, ':' )) ) {
  1832. X            base = path;
  1833. X         }
  1834. X         else {
  1835. X            ++base;
  1836. X         }
  1837. X      }
  1838. X      else {
  1839. X         ++base;
  1840. X      }
  1841. X
  1842. X      if ( vers )  *vers ='\0';
  1843. X      if ( ext  &&  (!stricmp(ext, ".COM") || !stricmp(ext, ".EXE")) ) {
  1844. X          ext = '\0';
  1845. X      }
  1846. X
  1847. X      return  base;
  1848. X   }
  1849. X
  1850. #else
  1851. #ifdef AmigaDOS
  1852. X      /* amiga version of basename() */
  1853. # ifdef __ANSI_C__
  1854. X   char *basename( char  path[] )
  1855. # else
  1856. X   char *basename( path ) char  path[];
  1857. # endif
  1858. X   {
  1859. X      return   path;
  1860. X   }
  1861. #else
  1862. #define PATH_SEP  '/'     /* default path-separator character */
  1863. X
  1864. X      /* default version of basename() */
  1865. # ifdef __ANSI_C__
  1866. X   char *basename( char  path[] )
  1867. # else
  1868. X   char *basename( path ) char  path[];
  1869. # endif
  1870. X   {
  1871. X      char *base = strrchr( path, PATH_SEP );
  1872. X
  1873. #if ( defined(MSDOS) || defined(OS2) )
  1874. X      /* remove the extension from .EXE, .COM, .BAT, and .CMD files */
  1875. # ifdef OS2
  1876. X      if ( ext  &&  (!stricmp(ext, ".CMD") )  *ext = '\0';
  1877. # else
  1878. X      if ( ext  &&  (!stricmp(ext, ".BAT") )  *ext = '\0';
  1879. # endif
  1880. X
  1881. X      if ( ext  &&  (!stricmp(ext, ".COM") || !stricmp(ext, ".EXE")) ) {
  1882. X          ext = '\0';
  1883. X      }
  1884. #endif
  1885. X
  1886. X      if ( !base ) {
  1887. #if ( defined(MSDOS) || defined(OS2) )
  1888. X         base = strrchr( path, '\\' );
  1889. X         if ( base )  return  (base + 1);
  1890. X         if ( path[ 1 ] == ':' )  return  (path + 2);  /* just remove drive */
  1891. X         return  (base + 1);
  1892. #endif
  1893. X         return  path;
  1894. X      }
  1895. X      else {
  1896. X         return  (base + 1);
  1897. X      }
  1898. X   }
  1899. #endif
  1900. #endif
  1901. X
  1902. X
  1903. /***************************************************************************
  1904. ** ^FUNCTION: indent_para - print a hanging indented paragraph
  1905. **
  1906. ** ^SYNOPSIS:
  1907. */
  1908. #ifndef __ANSI_C__
  1909. X   VOID indent_para(fp, maxcols, margin, title, indent, text)
  1910. /*
  1911. ** ^PARAMETERS:
  1912. */
  1913. X   FILE *fp;
  1914. /*    -- the stream to which output is sent
  1915. */
  1916. X   int maxcols;
  1917. /*    -- the maximum width (in characters) of the output
  1918. */
  1919. X   int margin;
  1920. /*    -- the number of spaces to use as the left margin
  1921. */
  1922. X   char *title;
  1923. /*    -- the paragraph title
  1924. */
  1925. X   int indent;
  1926. /*    -- the distance between the title and the paragraph body
  1927. */
  1928. X   char *text;
  1929. /*    -- the body of the paragraph
  1930. */
  1931. #endif  /* !__ANSI_C__ */
  1932. X
  1933. /* ^DESCRIPTION:
  1934. **    Indent_para will print on fp, a titled, indented paragraph as follows:
  1935. **
  1936. **    <----------------------- maxcols --------------------------->
  1937. **    <--- margin -->     <-- indent -->
  1938. **                   title              This is the first sentence
  1939. **                                      of the paragraph. Etc ...
  1940. **
  1941. ** ^REQUIREMENTS:
  1942. **    maxcols and indent must be positive numbers with maxcols > indent
  1943. **
  1944. ** ^SIDE-EFECTS:
  1945. **    Output is printed to fp.
  1946. **
  1947. ** ^RETURN-VALUE:
  1948. **    None.
  1949. **
  1950. ** ^ALGORITHM:
  1951. **    Print the paragraph title and then print the text.
  1952. **    Lines are automatically adjusted so that each one starts in the
  1953. **    appropriate column.
  1954. ***^^**********************************************************************/
  1955. #ifdef __ANSI_C__
  1956. X   void indent_para( FILE *fp, int maxcols, int margin,
  1957. X                     const char *title, int indent, const char *text )
  1958. #endif
  1959. {
  1960. X   register int idx = 0;
  1961. X   BOOL first_line = TRUE;
  1962. X   int  text_len = strlen(text);
  1963. X   char ch;
  1964. X
  1965. X   /* print the title */
  1966. X      fprintf( fp, "%*s%-*s", margin, "", indent, title );
  1967. X
  1968. X   idx = maxcols - margin - indent;
  1969. X
  1970. X   if ( text_len <= idx )
  1971. X      fprintf(fp, "%s\n", text);
  1972. X   else
  1973. X      do {
  1974. X               /* backup to end of previous word */
  1975. X         while (idx  &&  !isspace(text[idx]))  --idx;
  1976. X         while (idx  &&  isspace(text[idx]))   --idx;
  1977. X
  1978. X            /* print leading whitespace */
  1979. X         if (!first_line)
  1980. X            fprintf(fp, "%*s%-*s", margin, "", indent, "");
  1981. X
  1982. X         ch = text[ ++idx ];
  1983. X         *((char *)text + idx) = '\0';
  1984. X         fprintf(fp, "%s\n", text);
  1985. X         *((char *)text + idx) = ch;
  1986. X         first_line = FALSE;
  1987. X         text = &(text[idx+1]);
  1988. X         text_len -= (idx+1);
  1989. X
  1990. X         while (isspace(*text)) {  /* goto next word */
  1991. X            ++text;
  1992. X            --text_len;
  1993. X         }
  1994. X
  1995. X         idx = maxcols - margin - indent;
  1996. X
  1997. X         if ( text_len <= idx )  /* print-last line */
  1998. X            fprintf(fp, "%*s%-*s%s\n", margin, "", indent, "", text);
  1999. X      } while ( text_len > idx );
  2000. }
  2001. X
  2002. X
  2003. #ifdef STRTEST
  2004. X
  2005. #define WS " \t\n\v\r\f\"'"
  2006. X
  2007. static char string2[] =  "      oh what      a beautiful -    morning!        ";
  2008. X
  2009. static char string[] =  "\n\
  2010. \t' ',  ARGREQ,          argStr,   Name,     'Name',\n\
  2011. \t'n',  ARGOPT|ARGLIST,  listStr,  Groups,   'newsGROUP (newsgroups test)',\n\
  2012. \t'c',  ARGOPT,          argInt,   RepCount, 'REPcount (number of reps)',\n\
  2013. \t'd',  ARGOPT,          argStr,   DirName,  'DIRname',\n\
  2014. \t'x',  ARGOPT,          argBool,  XFlag,    'Xflag (expand in X direction)',\n\
  2015. \t' ',  ARGOPT|ARGLIST,  listStr,  Argv,     'File',\n\
  2016. \tENDOFARGS\n\
  2017. ";
  2018. X
  2019. static char word_str[] = "HELP (print help and quit)";
  2020. X
  2021. main()
  2022. #ifdef __ANSI_C__
  2023. #endif
  2024. {
  2025. X   char **vector;
  2026. X   unsigned i, numtoks;
  2027. X
  2028. X   printf( "test of strtrim() and strsplit():\n\n" );
  2029. X
  2030. X   printf( "unparsed string='%s'\n", string2 );
  2031. X   printf( "ltrimmed string='%s'\n", strltrim( string2, WS ) );
  2032. X   printf( "rtrimmed string='%s'\n", strrtrim( string2, WS ) );
  2033. X
  2034. X   numtoks = strsplit( &vector, string, "," );
  2035. X   printf( "number of tokens=%d\n", numtoks );
  2036. X   for ( i = 0 ; i < numtoks ; i++ ) {
  2037. X      printf( "trimmed token[%d] = '%s'\n", i, strtrim( vector[i], WS ) );
  2038. X   }
  2039. X
  2040. X   exit( 0 );
  2041. }
  2042. X
  2043. #endif
  2044. SHAR_EOF
  2045. chmod 0664 parseargs/strfuncs.c ||
  2046. echo 'restore of parseargs/strfuncs.c failed'
  2047. Wc_c="`wc -c < 'parseargs/strfuncs.c'`"
  2048. test 34399 -eq "$Wc_c" ||
  2049.     echo 'parseargs/strfuncs.c: original size 34399, current size' "$Wc_c"
  2050. rm -f _shar_wnt_.tmp
  2051. fi
  2052. # ============= parseargs/strfuncs.h ==============
  2053. if test -f 'parseargs/strfuncs.h' -a X"$1" != X"-c"; then
  2054.     echo 'x - skipping parseargs/strfuncs.h (File already exists)'
  2055.     rm -f _shar_wnt_.tmp
  2056. else
  2057. > _shar_wnt_.tmp
  2058. echo 'x - extracting parseargs/strfuncs.h (Text)'
  2059. sed 's/^X//' << 'SHAR_EOF' > 'parseargs/strfuncs.h' &&
  2060. /***************************************************************************
  2061. ** ^FILE: strfuncs.h - string functions
  2062. **
  2063. ** ^DESCRIPTION:
  2064. **    External declarations for the functions implemented in strfuncs.c
  2065. **
  2066. ** ^HISTORY:
  2067. **    01/07/91    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  2068. ***^^**********************************************************************/
  2069. X
  2070. #ifndef STRFUNCS_H
  2071. #define STRFUNCS_H
  2072. X
  2073. #include <useful.h>
  2074. X
  2075. EXTERN  char  *strucpy      ARGS(( char *, const char * ));
  2076. EXTERN  char  *strlcpy      ARGS(( char *, const char * ));
  2077. EXTERN  char  *strupr       ARGS(( char * ));
  2078. EXTERN  char  *strlwr       ARGS(( char * ));
  2079. EXTERN  int    stricmp      ARGS(( const char *, const char * ));
  2080. EXTERN  int    strnicmp     ARGS(( const char *, const char *, size_t ));
  2081. X
  2082. #ifdef BSD
  2083. X   EXTERN  char  *strdup    ARGS(( const char * ));
  2084. X   EXTERN  char  *strpbrk   ARGS(( const char *, const char * ));
  2085. X   EXTERN  int    strspn    ARGS(( const char *, const char * ));
  2086. X   EXTERN  int    strcspn   ARGS(( const char *, const char * ));
  2087. #endif
  2088. X
  2089. EXTERN  char  *strltrim     ARGS(( char *, const char * ));
  2090. EXTERN  char  *strrtrim     ARGS(( char *, const char * ));
  2091. EXTERN  char  *strtrim      ARGS(( char *, const char * ));
  2092. EXTERN  int    strsplit     ARGS(( char ***, char *, const char * ));
  2093. EXTERN  char  *strjoin      ARGS(( const char **, const char * ));
  2094. EXTERN  char  *get_name     ARGS(( const char *, char * ));
  2095. EXTERN  char  *get_keyword  ARGS(( const char *, char * ));
  2096. EXTERN  int    match        ARGS(( const char *, const char * ));
  2097. EXTERN  char  *basename     ARGS(( char * ));
  2098. EXTERN  VOID   indent_para  ARGS(( FILE *, int, int,
  2099. X                                   const char *, int, const char * ));
  2100. X
  2101. #endif
  2102. SHAR_EOF
  2103. chmod 0664 parseargs/strfuncs.h ||
  2104. echo 'restore of parseargs/strfuncs.h failed'
  2105. Wc_c="`wc -c < 'parseargs/strfuncs.h'`"
  2106. test 1729 -eq "$Wc_c" ||
  2107.     echo 'parseargs/strfuncs.h: original size 1729, current size' "$Wc_c"
  2108. rm -f _shar_wnt_.tmp
  2109. fi
  2110. # ============= parseargs/syserr.c ==============
  2111. if test -f 'parseargs/syserr.c' -a X"$1" != X"-c"; then
  2112.     echo 'x - skipping parseargs/syserr.c (File already exists)'
  2113.     rm -f _shar_wnt_.tmp
  2114. else
  2115. > _shar_wnt_.tmp
  2116. echo 'x - extracting parseargs/syserr.c (Text)'
  2117. sed 's/^X//' << 'SHAR_EOF' > 'parseargs/syserr.c' &&
  2118. /*************************************************************************
  2119. ** ^FILE: syserr.c - error-message printing routines
  2120. **
  2121. ** ^DESCRIPTION:
  2122. **    This fill implements various routines for printing diagnostic
  2123. **    messages on standard diagnostic output (stderr). The routines are:
  2124. **
  2125. **       usrerr()  --  print message and any system message(s) and return
  2126. **       syserr()  --  print message and any system message(s) and exit
  2127. **       eprintf() --  print to stderr and return
  2128. **
  2129. ** ^HISTORY:
  2130. **    01/02/91    Brad Appleton    <brad@ssd.csd.harris.com>
  2131. **       - Changed to use varargs/stdargs
  2132. **       - Added structured comment blocks
  2133. **       - Added eprintf()
  2134. **
  2135. **    --/--/--    Peter da Silva    <peter@ferranti.com>
  2136. **
  2137. **    --/--/--    Eric P. Allman    <eric@Berkeley.EDU>     Created
  2138. ***^^**********************************************************************/
  2139. X
  2140. #include <stdio.h>
  2141. #include <useful.h>
  2142. /* #include <funclist.h> */
  2143. X
  2144. VERSIONID("$Header: syserr.c,v 2.0 89/12/24 00:56:31 eric Exp $");
  2145. X
  2146. extern  char *ProgName;
  2147. extern  int   errno;
  2148. EXTERN  int   vfprintf  ARGS((FILE *, const char *, va_list));
  2149. X
  2150. X
  2151. /***************************************************************************
  2152. ** ^FUNCTION: _error_message - generic message printing routine.
  2153. **
  2154. ** ^SYNOPSIS:
  2155. */
  2156. #ifndef __ANSI_C__
  2157. X   static VOID _error_message( format, ap )
  2158. /*
  2159. ** ^PARAMETERS:
  2160. */
  2161. X   char *format;
  2162. SHAR_EOF
  2163. true || echo 'restore of parseargs/syserr.c failed'
  2164. fi
  2165. echo 'End of  part 9'
  2166. echo 'File parseargs/syserr.c is continued in part 10'
  2167. echo 10 > _shar_seq_.tmp
  2168. exit 0
  2169. exit 0 # Just in case...
  2170. -- 
  2171. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2172. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2173. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2174. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2175.