home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume29 / parsearg / part07 < prev    next >
Encoding:
Text File  |  1992-05-18  |  43.0 KB  |  1,568 lines

  1. Newsgroups: comp.sources.misc
  2. From: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
  3. Subject:  v29i122:  parseargs - functions to parse command line arguments, Part07/10
  4. Message-ID: <1992May17.182453.28940@sparky.imd.sterling.com>
  5. X-Md4-Signature: 0995bf53dac855bf7503a064b6d1dcbd
  6. Date: Sun, 17 May 1992 18:24:53 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
  10. Posting-number: Volume 29, Issue 122
  11. Archive-name: parseargs/part07
  12. Environment: UNIX, VMS, MS-DOS, OS/2, Amiga
  13. Supersedes: parseargs: Volume 17, Issue 46-57
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 7 (of 10)."
  22. # Contents:  strfuncs.c
  23. # Wrapped by brad@hcx1 on Thu May  7 12:12:26 1992
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'strfuncs.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'strfuncs.c'\"
  27. else
  28. echo shar: Extracting \"'strfuncs.c'\" \(40645 characters\)
  29. sed "s/^X//" >'strfuncs.c' <<'END_OF_FILE'
  30. X/**************************************************************************
  31. X** ^FILE: strfuncs.c - Miscellaneous string functions for parseargs
  32. X**
  33. X** ^DESCRIPTION:
  34. X**    This file implements a wide variety of functions to manipulate
  35. X**    strings in way way or another. Some of the functions may already
  36. X**    be included in the standard library of some C compilers.
  37. X**
  38. X**    The following functions are implemented:
  39. X**
  40. X**       strucpy() -- copy a string and map to uppercase
  41. X**       strlcpy() -- copy a string and map to lowercase
  42. X**       strupr() -- convert a string to uppercase
  43. X**       strlwr() -- convert a string to lowercase
  44. X**       stricmp() -- case insensitive comparison of strings
  45. X**       strnicmp() -- case insensitive length-limited comparison of strings
  46. X**       strdup() -- return a (newly allocated) copy of a string
  47. X**       strndup() -- return a (newly allocated) copy of a prefix of a string
  48. X**       strpbrk() -- return first occurrence of character in a set
  49. X**       strspn() -- return length of initial prefix of a character set
  50. X**       strcspn() -- return length of initial prefix of a character set
  51. X**       strltrim() -- trim leftmost (leading) characters in a string
  52. X**       strrtrim() -- trim rightmost (trailing) characters in a string
  53. X**       strtrim() -- trim leading and trailing characters in a string
  54. X**       strsplit() -- split a string up into a vector of tokens
  55. X**       strjoin() -- join a vector of tokens into a single string
  56. X**       get_argpfx() -- return the length of the first part of the string
  57. X**       get_argdesc() -- return the description (second part) of the string
  58. X**       get_argname() -- return the aname (argument-name) of an argument
  59. X**       get_kwdname() -- return the sname (keyword-name) of an argument
  60. X**       match() -- match two keywords (case insensitive) upto a unique prefix
  61. X**       basename() -- remove the leading directories (and disks) from a path
  62. X**       indent_para() -- print an indented hanging paragraph
  63. X**
  64. X** ^HISTORY:
  65. X**
  66. X**    12/16/91     Brad Appleton     <brad@ssd.csd.harris.com>
  67. X**    - add strndup()
  68. X**
  69. X**    11/26/91     Brad Appleton     <brad@ssd.csd.harris.com>
  70. X**    - added the following to indent_para(). If last arg is 0,
  71. X**      then the whole length is used.
  72. X**
  73. X**    08/27/91     Earl Chew     <cechew@bruce.cs.monash.edu.au>
  74. X**    - add extra length argument to indent_para().
  75. X**    - add FORCE_KWDCASE() macro
  76. X**    - add non-writable strings support to get_argname() and
  77. X**      get_kwdname()
  78. X**    - add get_argpfx() and get_argdesc() for non-writable strings
  79. X**      support
  80. X**    - allow zero length string for strsplit()
  81. X**
  82. X**    01/02/91     Brad Appleton     <brad@ssd.csd.harris.com>     Created
  83. X**    - changed from file misc.c to this name and added all of the strxxx
  84. X**      functions (plus got rid of some unused functions).
  85. X**
  86. X**    --/--/--    Peter da Silva    <peter@ferranti.com>    
  87. X**
  88. X**    --/--/--    Eric P. Allman    <eric@Berkeley.EDU>     Created
  89. X***^^**********************************************************************/
  90. X
  91. X#include <stdio.h>
  92. X#include <ctype.h>
  93. X#include <useful.h>
  94. X
  95. X#ifdef vms
  96. X# include <ssdef.h>
  97. X#endif
  98. X
  99. X#include "strfuncs.h"
  100. X
  101. XEXTERN  VOID   syserr  ARGS((const char *, ...));
  102. X
  103. Xstatic CONST char WhiteSpace[] = " \t\n\r\v\f";
  104. X
  105. X#define c_ARG_SEP '='
  106. X#if ( defined(unix_style)  ||  defined(ibm_style) )
  107. X# define  FORCE_KWDCASE(s)       strlwr(s)
  108. X# define  TO_KWDCASE(c)          TOLOWER(c)
  109. X# define  KWDCASECOPY(dest,src)  strlcpy(dest,src)
  110. X#else
  111. X# define  FORCE_KWDCASE(s)       strupr(s)
  112. X# define  TO_KWDCASE(c)          TOUPPER(c)
  113. X# define  KWDCASECOPY(dest,src)  strucpy(dest,src)
  114. X#endif
  115. X
  116. X
  117. X/***************************************************************************
  118. X** ^FUNCTION: strucpy, strlcpy - copy dest to src, mapping to upper/lower case
  119. X**
  120. X** ^SYNOPSIS:
  121. X**
  122. X**    char *strucpy( dest, src )
  123. X**    char *strlcpy( dest, src )
  124. X**
  125. X** ^PARAMETERS:
  126. X**    char *dest;
  127. X**    -- the address to start copying to
  128. X**
  129. X**    char *src;
  130. X**    -- the address to start copying from
  131. X**
  132. X** ^DESCRIPTION:
  133. X**    Strlcpy (strucpy) copies src into dest (upto and including the
  134. X**    terminating NUL byte) and all uppercase (lowercase) characters in
  135. X**    src are mapped to lowercase (uppercase) before being copied into dest.
  136. X**
  137. X** ^REQUIREMENTS:
  138. X**    Dest must be non-null, and large enough to hold the copied result.
  139. X**
  140. X** ^SIDE-EFFECTS:
  141. X**    Dest is (re)written
  142. X**
  143. X** ^RETURN-VALUE:
  144. X**    Address of dest.
  145. X**
  146. X** ^ALGORITHM:
  147. X**    Trivial.
  148. X***^^**********************************************************************/
  149. X#ifdef __ANSI_C__
  150. X   char *strucpy( char *dest, const char *src )
  151. X#else
  152. X   char *strucpy( dest, src )  char *dest, *src;
  153. X#endif
  154. X{
  155. X   register char  *s1 = dest;
  156. X   register CONST char  *s2 = src;
  157. X
  158. X   if ( !s2 )  return  CHARNULL;
  159. X
  160. X   for ( ; *s2 ; s1++, s2++ ) {
  161. X      *s1 = TOUPPER( *s2 );
  162. X   }
  163. X   *s1 = '\0';
  164. X
  165. X   return   s1;
  166. X}
  167. X
  168. X
  169. X#ifdef __ANSI_C__
  170. X   char *strlcpy( char *dest, const char *src )
  171. X#else
  172. X   char *strlcpy( dest, src )  char *dest, *src;
  173. X#endif
  174. X{
  175. X   register char  *s1 = dest;
  176. X   register CONST char  *s2 = src;
  177. X
  178. X   if ( !s2 )  return  CHARNULL;
  179. X
  180. X   for ( ; *s2 ; s1++, s2++ ) {
  181. X      *s1 = TOLOWER( *s2 );
  182. X   }
  183. X   *s1 = '\0';
  184. X
  185. X   return   s1;
  186. X}
  187. X
  188. X
  189. X/***************************************************************************
  190. X** ^FUNCTION: strupr, strlwr - convert a string to all upper/lower case
  191. X**
  192. X** ^SYNOPSIS:
  193. X**    char *strupr( str )
  194. X**    char *strlwr( str )
  195. X**
  196. X** ^PARAMETERS:
  197. X**    char *str;
  198. X**    -- the string to be converted
  199. X**
  200. X** ^DESCRIPTION:
  201. X**    Strupr (strlwr) converts all lowercase (uppercase) characters in <str>
  202. X**    to uppercase (lowercase) and returns the address of <str>.
  203. X**
  204. X** ^REQUIREMENTS:
  205. X**    str should be non-null and non-empty.
  206. X**
  207. X** ^SIDE-EFFECTS:
  208. X**    str is overwritten with the uppercase (lowercase) result.
  209. X**
  210. X** ^RETURN-VALUE:
  211. X**    Address of str.
  212. X**
  213. X** ^ALGORITHM:
  214. X**    Trivial.
  215. X***^^**********************************************************************/
  216. X#ifdef __ANSI_C__
  217. X   char *strupr( char *str )
  218. X#else
  219. X   char *strupr( str )  char *str;
  220. X#endif
  221. X{
  222. X   char *p = str;
  223. X
  224. X   for ( ; p && *p ; p++ ) {
  225. X      if ( islower(*p) )  *p = toupper(*p);
  226. X   }
  227. X
  228. X   return   str;
  229. X}
  230. X
  231. X
  232. X#ifdef __ANSI_C__
  233. X   char *strlwr( char *str )
  234. X#else
  235. X   char *strlwr( str )  char *str;
  236. X#endif
  237. X{
  238. X   char *p = str;
  239. X
  240. X   for ( ; p && *p ; p++ ) {
  241. X      if ( isupper(*p) )  *p = tolower(*p);
  242. X   }
  243. X
  244. X   return   str;
  245. X}
  246. X
  247. X
  248. X/***************************************************************************
  249. X** ^FUNCTION: stricmp, strnicmp - case insensitive string comparison
  250. X**
  251. X** ^SYNOPSIS:
  252. X**    int stricmp( s1, s2 )
  253. X**    int strnicmp( s1, s2, n )
  254. X**
  255. X** ^PARAMETERS:
  256. X**    char *s1;
  257. X**    -- first string to compare
  258. X**
  259. X**    char *s2;
  260. X**    -- second string to compare
  261. X**
  262. X**    size_t  n;
  263. X**    -- The number of characters to compare
  264. X**
  265. X** ^DESCRIPTION:
  266. X**    Stricmp (strnicmp) is identical to strcmp (strncmp) except that it
  267. X**    it performs a case-insensitive comparison of characters.
  268. X**
  269. X** ^REQUIREMENTS:
  270. X**    Both s1 and s2 should be non-null and non-empty
  271. X**
  272. X** ^SIDE-EFFECTS:
  273. X**    None.
  274. X**
  275. X** ^RETURN-VALUE:
  276. X**    < 0    if s1 < s2
  277. X**    = 0    if s1 matches s2
  278. X**    > 0    if s1 > s2
  279. X**
  280. X** ^ALGORITHM:
  281. X**    Trivial.
  282. X***^^**********************************************************************/
  283. X#ifdef __ANSI_C__
  284. X   int stricmp( const char *str1, const char *str2 )
  285. X#else
  286. X   int stricmp( str1, str2 ) char *str1, *str2;
  287. X#endif
  288. X{
  289. X   register  CONST char *s1 = str1, *s2 = str2;
  290. X   register  char  c1, c2;
  291. X
  292. X   if ( s1 == s2 )  return   0;
  293. X   if ( !s1 )       return  -1;
  294. X   if ( !s2 )       return   1;
  295. X
  296. X   for ( ; *s1 && *s2 ; s1++ , s2++ ) {
  297. X      c1 = TOLOWER( *s1 );
  298. X      c2 = TOLOWER( *s2 );
  299. X
  300. X      if (c1 != c2)  return  (int)(c1 -c2);
  301. X   }
  302. X   return   (*s1 == *s2) ? 0 : (int)(*s1 - *s2);
  303. X}
  304. X
  305. X
  306. X#ifdef __ANSI_C__
  307. X   int strnicmp( const char *str1, const char *str2, size_t len )
  308. X#else
  309. X   int strnicmp( str1, str2, len ) char *str1, *str2; size_t  len;
  310. X#endif
  311. X{
  312. X   register  CONST char *s1 = str1, *s2 = str2;
  313. X   register  char  c1, c2;
  314. X
  315. X   if ( s1 == s2 )  return   0;
  316. X   if ( !s1 )       return  -1;
  317. X   if ( !s2 )       return   1;
  318. X
  319. X   for ( ; *s1 && *s2 && len ; s1++ , s2++ , len-- ) {
  320. X      c1 = TOLOWER( *s1 );
  321. X      c2 = TOLOWER( *s2 );
  322. X
  323. X      if (c1 != c2)  return  (int)(c1 -c2);
  324. X   }
  325. X   return   (!len  ||  (*s1 == *s2)) ? 0 : (int)(*s1 - *s2);
  326. X}
  327. X
  328. X
  329. X/***************************************************************************
  330. X** ^FUNCTION: strdup - copy a string
  331. X**
  332. X** ^SYNOPSIS:
  333. X*/
  334. X# ifndef __ANSI_C__
  335. X   char *strdup( str )
  336. X/*
  337. X** ^PARAMETERS:
  338. X*/
  339. X   char *str;
  340. X/*    -- the string to replicate
  341. X*/
  342. X# endif  /* !__ANSI_C__ */
  343. X
  344. X/* ^DESCRIPTION:
  345. X**    Strdup allocates storrage and copies the given string into the
  346. X**    newly acquired space (returning its address). The returned result
  347. X**    should be deallocated using free().
  348. X**
  349. X** ^REQUIREMENTS:
  350. X**    str should be non-null
  351. X**
  352. X** ^SIDE-EFFECTS:
  353. X**    None.
  354. X**
  355. X** ^RETURN-VALUE:
  356. X**    Address of the newly allocated string.
  357. X**
  358. X** ^ALGORITHM:
  359. X**    Trivial.
  360. X***^^**********************************************************************/
  361. X# ifdef __ANSI_C__
  362. X   char *strdup( const char *str )
  363. X# endif
  364. X{
  365. X  unsigned len = strlen(str) + 1;
  366. X  char *p = (char *)malloc( len * sizeof(char) );
  367. X
  368. X  if ( !p )  syserr( "malloc failed in strdup()" );
  369. X  strcpy(p, str);
  370. X
  371. X  return p;
  372. X}
  373. X
  374. X
  375. X/***************************************************************************
  376. X** ^FUNCTION: strndup - copy a prefix of a string
  377. X**
  378. X** ^SYNOPSIS:
  379. X*/
  380. X# ifndef __ANSI_C__
  381. X   char *strndup( str, len )
  382. X/*
  383. X** ^PARAMETERS:
  384. X*/
  385. X   char *str;
  386. X/*    -- the string to replicate
  387. X*/
  388. X   unsigned  len;
  389. X/*    -- the number of characters to be replicated
  390. X*/
  391. X# endif  /* !__ANSI_C__ */
  392. X
  393. X/* ^DESCRIPTION:
  394. X**    Strndup allocates storrage and copies the the first "len" characters
  395. X**    of the given string into the newly acquired space (returning its
  396. X**    address). The returned result should be deallocated using free().
  397. X**
  398. X** ^REQUIREMENTS:
  399. X**    str should be non-null
  400. X**
  401. X** ^SIDE-EFFECTS:
  402. X**    None.
  403. X**
  404. X** ^RETURN-VALUE:
  405. X**    Address of the newly allocated string.
  406. X**
  407. X** ^ALGORITHM:
  408. X**    Trivial.
  409. X***^^**********************************************************************/
  410. X# ifdef __ANSI_C__
  411. X   char *strndup( const char *str, unsigned len )
  412. X# endif
  413. X{
  414. X  char *p = (char *)malloc( (len + 1) * sizeof(char) );
  415. X
  416. X  if ( !p )  syserr( "malloc failed in strndup()" );
  417. X  strncpy(p, str, len);
  418. X
  419. X  return p;
  420. X}
  421. X
  422. X
  423. X#ifdef BSD
  424. X
  425. X/***************************************************************************
  426. X** ^FUNCTION: strpbrk - return the first occurrence of characters in a string
  427. X**
  428. X** ^SYNOPSIS:
  429. X*/
  430. X#ifndef __ANSI_C__
  431. X   char *strpbrk( str1, str2 )
  432. X/*
  433. X** ^PARAMETERS:
  434. X*/
  435. X   char *str1;
  436. X/*    -- the string to be searched
  437. X*/
  438. X   char *str2;
  439. X/*    -- the set of characters to be located
  440. X*/
  441. X#endif  /* !__ANSI_C__ */
  442. X
  443. X/* ^DESCRIPTION:
  444. X**    Strpbrk will attempt to locate the first occurence in str1 of any 
  445. X**    character from str2 and return the address of the first such
  446. X**    occurrence. If str1 contains NO characters from str2, then NULL
  447. X**    is returned.
  448. X**
  449. X** ^REQUIREMENTS:
  450. X**    Both str1 and str2 should be non-null and non-empty
  451. X**
  452. X** ^SIDE-EFFECTS:
  453. X**    None.
  454. X**
  455. X** ^RETURN-VALUE:
  456. X**    A pointer to the first occurence in str1 of any char from str2.
  457. X**
  458. X** ^ALGORITHM:
  459. X**    - foreach char in str1
  460. X**       - if char is in str2, return the address of char
  461. X**      end-for
  462. X**    - if we have reached the end of str1, return NULL
  463. X***^^**********************************************************************/
  464. X#ifdef __ANSI_C__
  465. X   char *strpbrk( const char *str1, const char *str2 )
  466. X#endif
  467. X{
  468. X   register CONST char *s1 =  str1, *s2 = str2;
  469. X
  470. X   if ( !s1 || !*s1 || !s2 || !*s2 )  return  CHARNULL;
  471. X
  472. X   for ( ; *s1 ; s1++ )  {
  473. X      if ( strchr(s2, *s1) )  return (char *)s1;
  474. X   }
  475. X
  476. X   return  CHARNULL;
  477. X}
  478. X
  479. X
  480. X/***************************************************************************
  481. X** ^FUNCTION: strspn, strcspn - identify leading runs of characters
  482. X**
  483. X** ^SYNOPSIS:
  484. X**    char *strspn( str1, str2 )
  485. X**    char *strcspn( str1, str2 )
  486. X**
  487. X** ^PARAMETERS:
  488. X**    char *str1;
  489. X**    -- the string to be searched
  490. X**
  491. X**    char *str2;
  492. X**    -- the string to be searched
  493. X**
  494. X** ^DESCRIPTION:
  495. X**    Strspn (strcspn) attempts to determine the length of the longest
  496. X**    leading prefix of str1 that consists entirely of character from
  497. X**    (not from) str2.
  498. X**
  499. X** ^REQUIREMENTS:
  500. X**    Both str1 and str2 should be non-null and non-empty.
  501. X**
  502. X** ^SIDE-EFFECTS:
  503. X**    None.
  504. X**
  505. X** ^RETURN-VALUE:
  506. X**    The length of the initial prefix in str1 consisting entirely
  507. X**    of characters from (not from) str2.
  508. X**
  509. X** ^ALGORITHM:
  510. X**    - length = 0
  511. X**    - for each char in str1
  512. X**       - if char is in str2 (for strcspn) or not in str2 (for strcspn)
  513. X**            then return length
  514. X**       - else
  515. X**            add 1 to length
  516. X**         end-if
  517. X**      end-for
  518. X**    - if end-of-string then return length
  519. X**
  520. X***^^**********************************************************************/
  521. X#ifdef __ANSI_C__
  522. X   int strspn( const char *str1, const char *str2 )
  523. X#else
  524. X   int strspn( str1, str2 )  char *str1, *str2;
  525. X#endif
  526. X{
  527. X   register CONST char  *s1 = str1, *s2 = str2;
  528. X   int len = 0;
  529. X
  530. X   if ( !s1 || !*s1 || !s2 || !*s2 )  return  0;
  531. X   while ( *s1  &&  strchr(s2, *s1++) )  ++len;
  532. X   return  len;
  533. X}
  534. X
  535. X
  536. X#ifdef __ANSI_C__
  537. X   int strcspn( const char *str1, const char *str2 )
  538. X#else
  539. X   int strcspn( str1, str2 )  char *str1, *str2;
  540. X#endif
  541. X{
  542. X   register CONST char  *s1 = str1, *s2 = str2;
  543. X   int len = 0;
  544. X
  545. X   if ( !s1 || !*s1 || !s2 || !*s2 )  return  0;
  546. X   while ( *s1  &&  !strchr(s2, *s1++) )  ++len;
  547. X   return  len;
  548. X}
  549. X
  550. X#endif  /* BSD */
  551. X
  552. X
  553. X/***************************************************************************
  554. X** ^FUNCTION: strltrim, strrtrim, strtrim - trim leading/trailing characters
  555. X**
  556. X** ^SYNOPSIS:
  557. X**    char *strltrim( str, charset )
  558. X**    char *strrtrim( str, charset )
  559. X**    char *strtrim( str, charset )
  560. X**
  561. X** ^PARAMETERS:
  562. X**    char *str;
  563. X**    -- the string to be trimmed
  564. X**
  565. X**    char *charset;
  566. X**    -- the set of characters to be trimmed
  567. X**
  568. X** ^DESCRIPTION:
  569. X**    Strltrim removes from str, all leftmost (leading) characters occurring
  570. X**    in charset.
  571. X**
  572. X**    Strrtrim removes from str, all rightmost (trailing) characters occurring
  573. X**    in charset.
  574. X**
  575. X**    Strtrim removes from str, all leading and trailing characters occurring
  576. X**    in charset.
  577. X**
  578. X**    For each of these functions, if charset is NULL or empty, then the set
  579. X**    of whitespace characters (space, tab, newline, carriage-return, form-feed
  580. X**    and vertical-tab) is assumed.
  581. X**
  582. X** ^REQUIREMENTS:
  583. X**    str should be non-null and non-empty.
  584. X**
  585. X** ^SIDE-EFFECTS:
  586. X**    characters may be removed from the beginning and/or end of str.
  587. X**
  588. X** ^RETURN-VALUE:
  589. X**    Address of str.
  590. X**
  591. X** ^ALGORITHM:
  592. X**    Trivial.
  593. X***^^**********************************************************************/
  594. X#ifdef __ANSI_C__
  595. X   char *strltrim( char *str, const char *charset )
  596. X#else
  597. X   char *strltrim( str, charset )  char *str, *charset;
  598. X#endif
  599. X{
  600. X   register   int   i;
  601. X
  602. X   if ( !str  ||  !*str )   return   str;
  603. X      /* if delim-string is NULL, whitespace is used */
  604. X   if ( !charset )   charset = WhiteSpace;
  605. X
  606. X   i = strspn( str, charset );
  607. X   if ( i > 0 )  strcpy( str, &(str[i]) );
  608. X
  609. X   return   str;
  610. X}
  611. X
  612. X
  613. X#ifdef __ANSI_C__
  614. X   char *strrtrim( char *str, const char *charset )
  615. X#else
  616. X   char *strrtrim( str, charset )  char *str, *charset;
  617. X#endif
  618. X{
  619. X   register   int   i;
  620. X
  621. X   if ( !str  ||  !*str )   return   str;
  622. X   if ( !charset )   charset = WhiteSpace;
  623. X   for ( i = strlen(str) - 1 ;
  624. X            ( i >= 0 ) && (strchr( charset, str[i] )) ;
  625. X            i--
  626. X         ) ;
  627. X
  628. X   str[i+1] = '\0';
  629. X
  630. X   return   str;
  631. X}
  632. X
  633. X
  634. X#ifdef __ANSI_C__
  635. X   char *strtrim( char *str, const char *charset )
  636. X#else
  637. X   char *strtrim( str, charset )  char *str, *charset;
  638. X#endif
  639. X{
  640. X   register   int   i;
  641. X
  642. X   if ( !str  ||  !*str )   return   str;
  643. X   if ( !charset )   charset = WhiteSpace;
  644. X   i = strspn( str, charset );
  645. X   if ( i > 0 )  strcpy( str, &(str[i]) );
  646. X
  647. X   for ( i = strlen(str) - 1 ;
  648. X            ( i >= 0 ) && (strchr( charset, str[i] )) ;
  649. X            i--
  650. X         ) ;
  651. X
  652. X   str[i+1] = '\0';
  653. X
  654. X   return   str;
  655. X}
  656. X
  657. X
  658. X/***************************************************************************
  659. X** ^FUNCTION: strsplit - split a string into tokens
  660. X**
  661. X** ^SYNOPSIS:
  662. X*/
  663. X#ifndef __ANSI_C__
  664. X   int  strsplit( vec, token_str, separators )
  665. X/*
  666. X** ^PARAMETERS:
  667. X*/
  668. X   char **vec[];
  669. X/*    -- pointer to the string vector to be allocated
  670. X*/
  671. X   char token_str[];
  672. X/*    -- the string to be split up
  673. X*/
  674. X   char separators[];
  675. X/*    -- the delimiters that separate tokens
  676. X*/
  677. X#endif  /* !__ANSI_C__ */
  678. X
  679. X/* ^DESCRIPTION:
  680. X**    Strsplit will split token_str up into  a vector of tokens that are
  681. X**    separated by one or more characters from <separators>. The number
  682. X**    of tokens found is returned and storage is allocated for the given
  683. X**    vector (which may later be deallocated using free()).
  684. X**
  685. X**    If <separators> is NULL or empty, then the set of whitespace characters
  686. X**    is used as the token delimiters.
  687. X**
  688. X** ^REQUIREMENTS:
  689. X**    vec must be non-NULL (it must be a valid address).
  690. X**    token_str should be non-null
  691. X**
  692. X** ^SIDE-EFFECTS:
  693. X**    All leading and trailing characters from <separators> are removed
  694. X**    from token_str. Furthermore, all remaining sequences in token_str
  695. X**    of characters from <separators> are replaced with a single NUL-byte.
  696. X**
  697. X**    Token_str holds the actual storage for all the strings in the newly
  698. X**    created vector.
  699. X**
  700. X** ^RETURN-VALUE:
  701. X**    The number of tokens parsed.
  702. X**
  703. X** ^ALGORITHM:
  704. X**    - count the number of tokens present while at the same time removing
  705. X**      all leading and trailing delimiters, and replacing all other sequences
  706. X**      of delimiters with the NUL character.
  707. X**    - allocate a vector large enough to point to all the token strings.
  708. X**    - for i in 0 .. (numtokens - 1) do
  709. X**         - vector[i] = token_str
  710. X**         - advance token_str to point at the next character past the
  711. X**           rightmost NUL-byte (which should be the start of the next token).
  712. X**      end-for
  713. X**    - vector[numtokens] = NUL
  714. X**    - return the number of tokens parsed.
  715. X***^^**********************************************************************/
  716. X#ifdef __ANSI_C__
  717. X   int strsplit( char **vec[], char token_str[], const char separators[] )
  718. X#endif
  719. X{
  720. X   register   char c, *pread, *pwrite;
  721. X   int   i, count = 0;
  722. X
  723. X   if ( !token_str )    token_str = "";
  724. X      /* if delim-string is NULL, whitespace is used */
  725. X   if ( !separators )   separators = WhiteSpace;
  726. X
  727. X      /* trim leading separators */
  728. X   pread = token_str;
  729. X   while ( strchr(separators, *pread) )   ++pread;
  730. X   if ( ! *pread )  return  0;
  731. X   token_str = pwrite = pread;
  732. X
  733. X      /*
  734. X      ** make first pass through string, counting # of tokens and
  735. X      ** separating all tokens by a single '\0'
  736. X      */
  737. X   for ( c = *pread++ ; c ; ) {
  738. X      if ( !strchr(separators, c) )   {
  739. X         do {
  740. X            *pwrite++ = c;
  741. X         } while ( (c = *pread++) && !strchr(separators, c) );
  742. X        *pwrite++ = '\0';
  743. X        ++count;
  744. X      }/*if*/
  745. X      while ( c && strchr(separators, c) )   c = *pread++;
  746. X   }/*for*/
  747. X
  748. X      /* allocate space for the caller's vector (remember NULL at the end) */
  749. X   (*vec) = (char **)malloc( (1 + count) * sizeof( char * ) );
  750. X   if ( !*vec )  syserr( "malloc failed in strsplit()" );
  751. X
  752. X      /* now go thru token-string again assigning pointers from vector */
  753. X   pread = token_str;
  754. X   for ( i = 0 ; i < count ; i++ ) {
  755. X      (*vec)[i] = pread;   /* assign pointer */
  756. X      pread += strlen( pread ) + 1;
  757. X   }/* end-for */
  758. X
  759. X      /* set up the trailing pointer to NULL at the end */
  760. X   (*vec)[ count ] = CHARNULL;
  761. X   return   count;
  762. X}
  763. X
  764. X
  765. X/***************************************************************************
  766. X** ^FUNCTION: strjoin - join a vector of tokens together
  767. X**
  768. X** ^SYNOPSIS:
  769. X*/
  770. X#ifndef __ANSI_C__
  771. X   char  *strjoin( argv, separator )
  772. X/*
  773. X** ^PARAMETERS:
  774. X*/
  775. X   char *argv[];
  776. X/*    -- pointer to the string vector to join together
  777. X*/
  778. X   char separator[];
  779. X/*    -- the the string to use to separate tokens (if NULL, " " is used)
  780. X*/
  781. X#endif  /* !__ANSI_C__ */
  782. X
  783. X/* ^DESCRIPTION:
  784. X**    Strjoin will make a single string out of the given vector by copying
  785. X**    all the tokens from the given vector (in order) to a newly allocated
  786. X**    string. Tokens will be separated by a single occurence of <separator>.
  787. X**
  788. X**    If <separator> is NULL then a single space is used as the separator.
  789. X**    If <separator> is empty, then no separator is used and the tokens are
  790. X**    simply concatenated together.
  791. X**
  792. X** ^REQUIREMENTS:
  793. X**    argv must be non-NULL (it must be a valid address), and must be
  794. X**    terminated by a pointer to NULL (argv[last+1] == NULL).
  795. X**
  796. X** ^SIDE-EFFECTS:
  797. X**    Storage is allocated.
  798. X**
  799. X** ^RETURN-VALUE:
  800. X**    The address of the newly-joined result (which should be deallocated
  801. X**    using free()). Returns NULL if nothing was joined.
  802. X**
  803. X** ^ALGORITHM:
  804. X**    - count the number of characters to place in the joined-result.
  805. X**    - allocate a string large-enough to copy the joined-result into.
  806. X**    - copy each string into the string (with <separator> between tokens).
  807. X**    - 0 return the result.
  808. X***^^**********************************************************************/
  809. X#ifdef __ANSI_C__
  810. X   char *strjoin( const char *argv[], const char separator[] )
  811. X#endif
  812. X{
  813. X   size_t  sz = 0;
  814. X   register char *p;
  815. X   register CONST char *a, **av;
  816. X   register int  seplen;
  817. X   char *result;
  818. X
  819. X      /* if argv is NULL, nothing to do */
  820. X   if ( !argv )  return  CHARNULL;
  821. X   if ( !separator )  separator = " ";
  822. X   seplen = strlen( separator );
  823. X
  824. X      /* figure out how much space we need */
  825. X   for ( av = argv ; *av ; av++ ) {
  826. X      if ( !**av )  continue;
  827. X      sz += strlen( *av );
  828. X      if ( seplen  &&  *(av + 1) )  sz += seplen;
  829. X   }
  830. X
  831. X      /* allocate space */
  832. X   result = (char *)malloc( (sz + 1) * sizeof(char) );
  833. X   if ( !result )  syserr( "malloc failed in strjoin()" );
  834. X
  835. X      /* join the strings together */
  836. X   *result = '\0';
  837. X   for ( av = argv, p = result ; (a = *av) ; av++ ) {
  838. X      if ( !*a )  continue;
  839. X      while ( (*p = *a++) ) ++p;  /* copy token */
  840. X      if ( seplen  &&  *(av + 1) ) {
  841. X         a = separator;
  842. X         while ( (*p = *a++) ) ++p;  /* copy separator */
  843. X      }/*end-if*/
  844. X   }/*end-for*/
  845. X
  846. X   return  result;
  847. X}
  848. X
  849. X
  850. X/***************************************************************************
  851. X** ^FUNCTION: get_argpfx - get the prefix portion of a string
  852. X**
  853. X** ^SYNOPSIS:
  854. X*/
  855. X#ifndef __ANSI_C__
  856. X   int get_argpfx( str )
  857. X/*
  858. X** ^PARAMETERS:
  859. X*/
  860. X   char *str;
  861. X/*    -- the string to parse for a description
  862. X*/
  863. X#endif  /* !__ANSI_C__ */
  864. X
  865. X/* ^DESCRIPTION:
  866. X**    Get_argdesc returns the length of the first portion of the string.
  867. X**
  868. X**    Two "portions" must be either separated by whitespace or the second
  869. X**    portion may be within "(),{},[], or <>" delimiters. The second
  870. X**    portion is assumed to begin with the first alphabetic following
  871. X**    separator.
  872. X**
  873. X** ^REQUIREMENTS:
  874. X**    str should be non-null and non-empty
  875. X**
  876. X** ^SIDE-EFFECTS:
  877. X**    None.
  878. X**
  879. X** ^RETURN-VALUE:
  880. X**    The length of the first portion.
  881. X**
  882. X** ^ALGORITHM:
  883. X**    - locate the end of the first portion by scanning for whitespace or
  884. X**      balanced delimiters.
  885. X***^^**********************************************************************/
  886. X#ifdef __ANSI_C__
  887. X   int get_argpfx( const char *str )
  888. X#endif
  889. X{
  890. X   register char  *description;
  891. X   static CONST char  whitespace[]  = " \t\n\r\f\v";
  892. X   static CONST char  beg_portion[] = "(<{[";
  893. X
  894. X   description = strpbrk( str, whitespace );
  895. X   if ( !description ) {
  896. X       description = strpbrk( str, beg_portion );
  897. X   }
  898. X
  899. X   return description ? description - str : strlen(str);
  900. X}
  901. X
  902. X
  903. X/***************************************************************************
  904. X** ^FUNCTION: get_argdesc - get the description portion of a string
  905. X**
  906. X** ^SYNOPSIS:
  907. X*/
  908. X#ifndef __ANSI_C__
  909. X   char *get_argdesc( str, len )
  910. X/*
  911. X** ^PARAMETERS:
  912. X*/
  913. X   char *str;
  914. X/*    -- the string to parse for a description
  915. X*/
  916. X   int *len;
  917. X/*    -- the pointer to the length
  918. X*/
  919. X#endif  /* !__ANSI_C__ */
  920. X
  921. X/* ^DESCRIPTION:
  922. X**    Get_argdesc returns a pointer to the second portion of the string
  923. X**    and also indicates how long it is.
  924. X**
  925. X**    Two "portions" must be either separated by whitespace or the second
  926. X**    portion may be within "(),{},[], or <>" delimiters. The second
  927. X**    portion is assumed to begin with the first alphabetic following
  928. X**    separator.
  929. X**
  930. X** ^REQUIREMENTS:
  931. X**    str should be non-null and non-empty
  932. X**
  933. X** ^SIDE-EFFECTS:
  934. X**    The length of the description is written to *len.
  935. X**
  936. X** ^RETURN-VALUE:
  937. X**    Address of the description (or NULL if the string has no description).
  938. X**
  939. X** ^ALGORITHM:
  940. X**    - locate the end of the first portion by scanning for whitespace or
  941. X**      balanced delimiters.
  942. X**    - locate the beginning of the second portion by scanning for the first
  943. X**      alpha-numeric following the end of the first portion.
  944. X**    - return the address of the description.
  945. X***^^**********************************************************************/
  946. X#ifdef __ANSI_C__
  947. X   char *get_argdesc( const char *str, int *len )
  948. X#endif
  949. X{
  950. X   register char  *description = CHARNULL;
  951. X   BOOL  is_end = FALSE, is_balanced = FALSE;
  952. X   char  *p;
  953. X   static CONST char  whitespace[]  = " \t\n\r\f\v";
  954. X   static CONST char  beg_portion[] = "(<{[";
  955. X   static CONST char  end_portion[] = ")>}]";
  956. X
  957. X   description = strpbrk( str, whitespace );
  958. X   if ( description ) {
  959. X      is_end = TRUE;
  960. X      while ( isspace(*++description) )  continue;  /* trim leading ' ' */
  961. X      if ( strchr(beg_portion, *description) ) {
  962. X            is_balanced = TRUE;
  963. X            ++description;
  964. X      }
  965. X   }
  966. X   else {
  967. X       description = strpbrk( str, beg_portion );
  968. X       if ( description ) {  /* skip leading '(' */
  969. X          is_end = is_balanced = TRUE;
  970. X          ++description;
  971. X       }
  972. X   }
  973. X
  974. X   if ( !description ) {
  975. X      *len = 0;
  976. X   }
  977. X   else {
  978. X      if ( is_balanced ) {  /* remove trailing ')' */
  979. X         p = description + (strlen( description ) - 1);
  980. X         if ( !strchr(end_portion, *p) )  ++p;
  981. X         *len = p - description;
  982. X      }
  983. X      else {
  984. X         while ( !isalnum(*description) )  ++description;
  985. X         *len = strlen( description );
  986. X      }
  987. X   }
  988. X
  989. X   return  description;
  990. X}
  991. X
  992. X
  993. X/***************************************************************************
  994. X** ^FUNCTION: get_argname - return the aname (argument-name) of an argument
  995. X**
  996. X** ^SYNOPSIS:
  997. X*/
  998. X#ifndef __ANSI_C__
  999. X   char  *get_argname( s, buf )
  1000. X/*
  1001. X** ^PARAMETERS:
  1002. X*/
  1003. X   char *s;
  1004. X/*    -- the ad_prompt field of an ARGDESC struct
  1005. X*/
  1006. X   char *buf;
  1007. X/*    -- address to which the aname should be copied
  1008. X*/
  1009. X#endif  /* !__ANSI_C__ */
  1010. X
  1011. X/* ^DESCRIPTION:
  1012. X**    Get_argname will get the full argument name of the given argument
  1013. X**    (not just the keyword name) and copy it to buf.
  1014. X**
  1015. X** ^REQUIREMENTS:
  1016. X**    Both s and buf must be non-null and non-empty.
  1017. X**    buf must be large enough to hold the result.
  1018. X**
  1019. X** ^SIDE-EFFECTS:
  1020. X**    buf is overwritten.
  1021. X**
  1022. X** ^RETURN-VALUE:
  1023. X**    Address of the buffer containing the name.
  1024. X**
  1025. X** ^ALGORITHM:
  1026. X**    determine the name of an argument from its prompt
  1027. X**    and copy the result in the given buffer
  1028. X***^^**********************************************************************/
  1029. X#ifdef __ANSI_C__
  1030. X   char *get_argname( const char *s, char *buf )
  1031. X#endif
  1032. X{
  1033. X   register CONST char *p2;
  1034. X   int len;
  1035. X
  1036. X      /* see if sname and aname are separated by c_ARG_SEP
  1037. X      ** <buf> must be large enough to hold the result!
  1038. X      */
  1039. X   len = get_argpfx(s);
  1040. X   p2 = strchr( s, c_ARG_SEP );
  1041. X   if ( p2 && p2 < &s[len]) {
  1042. X      ++p2;
  1043. X      strncpy( buf, p2, len-(p2-s) );
  1044. X      buf[len-(p2-s)] = 0;
  1045. X      strlwr(buf);
  1046. X   }
  1047. X   else {
  1048. X      strncpy( buf, s, len );
  1049. X      buf[len] = 0;
  1050. X      strlwr(buf);
  1051. X   }
  1052. X   return   buf;
  1053. X}
  1054. X
  1055. X
  1056. X/***************************************************************************
  1057. X** ^FUNCTION: get_kwdname - get the sname (keyword name) of an argument
  1058. X**
  1059. X** ^SYNOPSIS:
  1060. X*/
  1061. X#ifndef __ANSI_C__
  1062. X   char  *get_kwdname( s, buf )
  1063. X/*
  1064. X** ^PARAMETERS:
  1065. X*/
  1066. X   char *s;
  1067. X/*    -- the ad_prompt field of an ARGDESC struct
  1068. X*/
  1069. X   char *buf;
  1070. X/*    -- address to which the sname should be copied
  1071. X*/
  1072. X#endif  /* !__ANSI_C__ */
  1073. X
  1074. X/* ^DESCRIPTION:
  1075. X**    Get_kwdname will get the keyword name of the given argument
  1076. X**    (not the entire argument name) and copy it to buf.
  1077. X**
  1078. X**    The sname (keyword-name) consists only of all uppercase characters
  1079. X**    from the ad_prompt field (in the order they occur). If the ad_prompt
  1080. X**    field contains NO uppercase characters, than the aname and the sname
  1081. X**    are equivalent (the entire string).
  1082. X**
  1083. X** ^REQUIREMENTS:
  1084. X**    Both s and buf must be non-null and non-empty.
  1085. X**    buf must be large enough to hold the result.
  1086. X**
  1087. X** ^SIDE-EFFECTS:
  1088. X**    buf is overwritten.
  1089. X*
  1090. X** ^RETURN-VALUE:
  1091. X**    Address of the buffer containing the keyword.
  1092. X**
  1093. X** ^ALGORITHM:
  1094. X**    determine the keyword of an argument from its prompt
  1095. X**    and copy the result in the given buffer
  1096. X***^^**********************************************************************/
  1097. X#ifdef __ANSI_C__
  1098. X   char *get_kwdname( const char *s, char *buf )
  1099. X#endif
  1100. X{
  1101. X   register char *p1 = (char *)s, *p2, ch;
  1102. X   int len;
  1103. X   BOOL caps = FALSE;
  1104. X
  1105. X   if ( !p1 )  return  CHARNULL;
  1106. X
  1107. X      /* see if sname and aname are separated by c_ARG_SEP */
  1108. X   len = get_argpfx( p1 );
  1109. X   p2 = strchr( p1, c_ARG_SEP );
  1110. X   if ( p2 && p2 < &p1[len]) {
  1111. X      strncpy( buf, p1, p2-p1);
  1112. X      buf[p2-p1] = 0;
  1113. X      FORCE_KWDCASE(buf);
  1114. X      return  buf;
  1115. X   }
  1116. X
  1117. X      /* copy string into buffer and convert it to desired case */
  1118. X      /* <buf> must be large enough to hold the result! */
  1119. X   for ( p2 = buf; *p1 && len != 0; p1++, len-- ) {
  1120. X      if ( isupper(*p1) ) {
  1121. X         if ( !caps ) {
  1122. X            caps = TRUE;
  1123. X            p2 = buf;
  1124. X         }
  1125. X         *p2++ = TO_KWDCASE(*p1);
  1126. X      }
  1127. X      else if ( !caps ) {
  1128. X         *p2++ = TO_KWDCASE(*p1);
  1129. X      }
  1130. X   }
  1131. X   *p2 = '\0';
  1132. X
  1133. X   return   buf;   /* return buffer address */
  1134. X}
  1135. X
  1136. X#ifndef amiga_style
  1137. X
  1138. X/***************************************************************************
  1139. X** ^FUNCTION: match - match a keyword against a prospective argument
  1140. X**
  1141. X** ^SYNOPSIS:
  1142. X*/
  1143. X#ifndef __ANSI_C__
  1144. X   int match( candidate, target )
  1145. X/*
  1146. X** ^PARAMETERS:
  1147. X*/
  1148. X   char *candidate;
  1149. X/*    -- the possible keyword argument
  1150. X*/
  1151. X   char *target;
  1152. X/*    -- the keyword to be matched
  1153. X*/
  1154. X#endif  /* !__ANSI_C__ */
  1155. X
  1156. X/* ^DESCRIPTION:
  1157. X**    Match will attempt to see if the candidate string matches the
  1158. X**    target string (case insensitive). First a match is tried on the
  1159. X**    sname of the keyword, then on the aname.  Candidate may be only
  1160. X**    a partial leading portion of the target as long as it is at least
  1161. X**    two characters long (unless the keyword is 1 character long).
  1162. X**
  1163. X**    No "partial" matching is accepted for AmigaDOS command-lines.
  1164. X**
  1165. X** ^REQUIREMENTS:
  1166. X**    Both candidate and target should be non-null and non-empty.
  1167. X**    target should be the ad_prompt field of an ARGDESC structure.
  1168. X**
  1169. X** ^SIDE-EFFECTS:
  1170. X**    None.
  1171. X**
  1172. X** ^RETURN-VALUE:
  1173. X*     < 0  if candidate < target
  1174. X**    = 0  if candidate matches target
  1175. X**    > 0  if candidate > target
  1176. X**
  1177. X** ^ALGORITHM:
  1178. X**    - attempt a partial match against the sname and return 0 if we succeed
  1179. X**    - attempt a partial match against the aname and return 0 if we succeed
  1180. X**    - if both the above fail return non-zero (no match).
  1181. X**    
  1182. X***^^**********************************************************************/
  1183. X
  1184. X/* rewritten 8/20/90 --BDA */
  1185. X#define MINLEN  2     /* minimum # of characters to match */
  1186. X
  1187. X#ifdef __ANSI_C__
  1188. X   int match ( const char *candidate, const char *target )
  1189. X#endif
  1190. X{
  1191. X   int  i, clen, tlen, too_short=0;
  1192. X   char  arg_targ[ 256 ], kwd_targ[ 256 ];
  1193. X
  1194. X
  1195. X      /* make kwd_targ the keyword portion of target */
  1196. X   (VOID) get_kwdname( target, kwd_targ );
  1197. X
  1198. X      /* match at least MINLEN characters if possible */
  1199. X   tlen = strlen( kwd_targ );
  1200. X   clen = strlen( candidate );
  1201. X   if ( (tlen >= MINLEN)   &&   (clen < MINLEN) ) {
  1202. X      ++too_short;      /* not long enough -- no match */
  1203. X   }
  1204. X
  1205. X#ifdef vms_style
  1206. X      /* if first two chars are NO then match at least MINLEN+2 chars */
  1207. X   if ( !strnicmp(kwd_targ, "NO", 2) ) {
  1208. X      if ( (tlen >= (MINLEN + 2))   &&   (clen < (MINLEN + 2)) ) {
  1209. X         ++too_short;      /* not long enough -- no match */
  1210. X      }
  1211. X   }
  1212. X#endif
  1213. X
  1214. X      /* first try to match prefix of the keyword portion */
  1215. X   i = (too_short) ? -1 : strnicmp(kwd_targ, candidate, clen);
  1216. X
  1217. X      /* did we match? */
  1218. X   if ( !i )  return  0;   /* yes! */
  1219. X
  1220. X   /* no! : compare the argument portion
  1221. X   **       match at least MINLEN characters if possible
  1222. X   */
  1223. X      /* make arg_targ the argument portion of target */
  1224. X   (VOID) get_argname( target, arg_targ );
  1225. X
  1226. X   tlen = strlen(arg_targ);
  1227. X   if ( (tlen >= MINLEN)   &&   (clen < MINLEN) ) {
  1228. X      return   -1;      /* not long enough -- no match */
  1229. X   }
  1230. X
  1231. X#ifdef vms_style
  1232. X   /* if first two chars are NO then match at least MINLEN+2 chars */
  1233. X   if ( !strnicmp(arg_targ, "no", 2) ) {
  1234. X      if ( (tlen >= (MINLEN + 2))   &&   (clen < (MINLEN + 2)) ) {
  1235. X         return   -1;      /* not long enough -- no match */
  1236. X      }
  1237. X   }
  1238. X#endif
  1239. X
  1240. X   return  strnicmp(arg_targ, candidate, clen);
  1241. X}
  1242. X
  1243. X
  1244. X/* here is the AmigaDOS version of match() */
  1245. X#else
  1246. X
  1247. X# ifdef __ANSI_C__
  1248. X   int match( const char *candidate, const char *target )
  1249. X# else
  1250. X   int match( candidate, target) char *candidate, *target;
  1251. X# endif
  1252. X{
  1253. X   char kwd_targ[ 256 ], arg_targ[ 256 ];
  1254. X   int rc;
  1255. X
  1256. X   (VOID) get_kwdname( target, kwd_targ );
  1257. X   rc = stricmp( kwd_targ, candidate );
  1258. X
  1259. X   if ( rc == 0 )  return  0;
  1260. X
  1261. X   (VOID) get_argname( target, arg_targ );
  1262. X   rc = stricmp( arg_targ, candidate );
  1263. X
  1264. X   return  rc;
  1265. X}
  1266. X
  1267. X#endif
  1268. X
  1269. X
  1270. X/***************************************************************************
  1271. X** ^FUNCTION: basename - return the last component of a pathname
  1272. X**
  1273. X** ^SYNOPSIS:
  1274. X**    char *basename( path )
  1275. X**
  1276. X** ^PARAMETERS:
  1277. X**    path;
  1278. X**    -- the pathname to be truncated.
  1279. X**
  1280. X** ^DESCRIPTION:
  1281. X**    Basename takes a pathname and strips of all leading components
  1282. X**    (except for the very last one) which refer to directories or
  1283. X**    disk-drives.
  1284. X**
  1285. X** ^REQUIREMENTS:
  1286. X**    path should be non-null, non-empty, and should correspond to a valid
  1287. X**    pathname (absolute or relative).
  1288. X**
  1289. X** ^SIDE-EFFECTS:
  1290. X**    None under Unix and AmigaDOS.
  1291. X**
  1292. X**    Under VMS, the file version is removed and any .COM or .EXE extension
  1293. X**    is also removed.
  1294. X**
  1295. X**    Under MS-DOS, any .EXE, .COM, or .BAT extension is removed.
  1296. X**
  1297. X**    Under OS/2, any .EXE, .COM, or .CMD extension is removed.
  1298. X**    
  1299. X** ^RETURN-VALUE:
  1300. X**    The address of the basename of the path.
  1301. X**
  1302. X** ^ALGORITHM:
  1303. X**    Trivial.
  1304. X***^^**********************************************************************/
  1305. X   /* should use '\\' for MS-DOS & OS/2 and use ']' for VMS */
  1306. X#ifdef vms
  1307. X#define PATH_SEP ']'
  1308. X
  1309. X      /* VAX/VMS version of basename */
  1310. X# ifdef __ANSI_C__
  1311. X   char *basename( char  path[] )
  1312. X# else
  1313. X   char *basename( path ) char  path[];
  1314. X# endif
  1315. X   {
  1316. X      char *base = strrchr( path, PATH_SEP );
  1317. X      char *vers = strrchr( path, ';' );
  1318. X      char *ext  = strrchr( path, '.' );
  1319. X
  1320. X      if ( !base ) {
  1321. X         if ( !(base = strrchr( path, ':' )) ) {
  1322. X            base = path;
  1323. X         }
  1324. X         else {
  1325. X            ++base;
  1326. X         }
  1327. X      }
  1328. X      else {
  1329. X         ++base;
  1330. X      }
  1331. X
  1332. X      if ( vers )  *vers ='\0';
  1333. X      if ( ext  &&  (!stricmp(ext, ".COM") || !stricmp(ext, ".EXE")) ) {
  1334. X          *ext = '\0';
  1335. X      }
  1336. X
  1337. X      return  base;
  1338. X   }
  1339. X
  1340. X#else
  1341. X#ifdef AmigaDOS
  1342. X      /* amiga version of basename() */
  1343. X# ifdef __ANSI_C__
  1344. X   char *basename( char  path[] )
  1345. X# else
  1346. X   char *basename( path ) char  path[];
  1347. X# endif
  1348. X   {
  1349. X      return   path;
  1350. X   }
  1351. X#else
  1352. X#define PATH_SEP  '/'     /* default path-separator character */
  1353. X
  1354. X      /* default version of basename() */
  1355. X# ifdef __ANSI_C__
  1356. X   char *basename( char  path[] )
  1357. X# else
  1358. X   char *basename( path ) char  path[];
  1359. X# endif
  1360. X   {
  1361. X      char *base = strrchr( path, PATH_SEP );
  1362. X
  1363. X#if ( defined(MSDOS) || defined(OS2) )
  1364. X      /* remove the extension from .EXE, .COM, .BAT, and .CMD files */
  1365. X# ifdef OS2
  1366. X      if ( ext  &&  (!stricmp(ext, ".CMD") )  *ext = '\0';
  1367. X# else
  1368. X      if ( ext  &&  (!stricmp(ext, ".BAT") )  *ext = '\0';
  1369. X# endif
  1370. X
  1371. X      if ( ext  &&  (!stricmp(ext, ".COM") || !stricmp(ext, ".EXE")) ) {
  1372. X          ext = '\0';
  1373. X      }
  1374. X#endif
  1375. X
  1376. X      if ( !base ) {
  1377. X#if ( defined(MSDOS) || defined(OS2) )
  1378. X         base = strrchr( path, '\\' );
  1379. X         if ( base )  return  (base + 1);
  1380. X         if ( path[ 1 ] == ':' )  return  (path + 2);  /* just remove drive */
  1381. X         return  (base + 1);
  1382. X#endif
  1383. X         return  path;
  1384. X      }
  1385. X      else {
  1386. X         return  (base + 1);
  1387. X      }
  1388. X   }
  1389. X#endif
  1390. X#endif
  1391. X
  1392. X
  1393. X/***************************************************************************
  1394. X** ^FUNCTION: indent_para - print a hanging indented paragraph
  1395. X**
  1396. X** ^SYNOPSIS:
  1397. X*/
  1398. X#ifndef __ANSI_C__
  1399. X   VOID indent_para(fp, maxcols, margin, title, indent, text, textlen)
  1400. X/*
  1401. X** ^PARAMETERS:
  1402. X*/
  1403. X   FILE *fp;
  1404. X/*    -- the stream to which output is sent
  1405. X*/
  1406. X   int maxcols;
  1407. X/*    -- the maximum width (in characters) of the output
  1408. X*/
  1409. X   int margin;
  1410. X/*    -- the number of spaces to use as the left margin
  1411. X*/
  1412. X   char *title;
  1413. X/*    -- the paragraph title
  1414. X*/
  1415. X   int indent;
  1416. X/*    -- the distance between the title and the paragraph body
  1417. X*/
  1418. X   char *text;
  1419. X/*    -- the body of the paragraph
  1420. X*/
  1421. X   int textlen;
  1422. X/*    -- the length of the body of the paragraph
  1423. X*/
  1424. X#endif  /* !__ANSI_C__ */
  1425. X
  1426. X/* ^DESCRIPTION:
  1427. X**    Indent_para will print on fp, a titled, indented paragraph as follows:
  1428. X**
  1429. X**    <----------------------- maxcols --------------------------->
  1430. X**    <--- margin -->     <-- indent -->
  1431. X**                   title              This is the first sentence
  1432. X**                                      of the paragraph. Etc ...
  1433. X**
  1434. X** ^REQUIREMENTS:
  1435. X**    maxcols and indent must be positive numbers with maxcols > indent
  1436. X**
  1437. X** ^SIDE-EFFECTS:
  1438. X**    Output is printed to fp.
  1439. X**
  1440. X** ^RETURN-VALUE:
  1441. X**    None.
  1442. X**
  1443. X** ^ALGORITHM:
  1444. X**    Print the paragraph title and then print the text.
  1445. X**    Lines are automatically adjusted so that each one starts in the
  1446. X**    appropriate column.
  1447. X***^^**********************************************************************/
  1448. X#ifdef __ANSI_C__
  1449. X   void indent_para( FILE *fp, int maxcols, int margin,
  1450. X                     const char *title, int indent, const char *text,
  1451. X                     int textlen )
  1452. X#endif
  1453. X{
  1454. X   register int idx = 0;
  1455. X   BOOL first_line = TRUE;
  1456. X   char ch;
  1457. X
  1458. X   if ( ! textlen )  textlen = strlen( text );
  1459. X
  1460. X   /* print the title */
  1461. X   fprintf( fp, "%*s%-*s", margin, "", indent, title );
  1462. X
  1463. X   idx = maxcols - margin - indent;
  1464. X
  1465. X   if ( textlen <= idx )
  1466. X      fprintf(fp, "%.*s\n", textlen, text);
  1467. X   else
  1468. X      do {
  1469. X               /* backup to end of previous word */
  1470. X         while (idx  &&  !isspace(text[idx]))  --idx;
  1471. X         while (idx  &&  isspace(text[idx]))   --idx;
  1472. X         idx++;
  1473. X
  1474. X            /* print leading whitespace */
  1475. X         if (!first_line)
  1476. X            fprintf(fp, "%*s%-*s", margin, "", indent, "");
  1477. X
  1478. X         fprintf(fp, "%.*s\n", idx, text);
  1479. X
  1480. X         first_line = FALSE;
  1481. X         text = &(text[idx+1]);
  1482. X         textlen -= (idx+1);
  1483. X
  1484. X         while (isspace(*text)) {  /* goto next word */
  1485. X            ++text;
  1486. X            --textlen;
  1487. X         }
  1488. X
  1489. X         idx = maxcols - margin - indent;
  1490. X
  1491. X         if ( textlen <= idx )  /* print-last line */
  1492. X            fprintf(fp, "%*s%-*s%.*s\n", margin, "", indent, "", textlen, text);
  1493. X      } while ( textlen > idx );
  1494. X}
  1495. X
  1496. X
  1497. X#ifdef STRTEST
  1498. X
  1499. X#define WS " \t\n\v\r\f\"'"
  1500. X
  1501. Xstatic char string2[] =  "      oh what      a beautiful -    morning!        ";
  1502. X
  1503. Xstatic char string[] =  "\n\
  1504. X\t' ',  ARGREQ,          argStr,   Name,     'Name',\n\
  1505. X\t'n',  ARGOPT|ARGLIST,  listStr,  Groups,   'newsGROUP (newsgroups test)',\n\
  1506. X\t'c',  ARGOPT,          argInt,   RepCount, 'REPcount (number of reps)',\n\
  1507. X\t'd',  ARGOPT,          argStr,   DirName,  'DIRname',\n\
  1508. X\t'x',  ARGOPT,          argBool,  XFlag,    'Xflag (expand in X direction)',\n\
  1509. X\t' ',  ARGOPT|ARGLIST,  listStr,  Argv,     'File',\n\
  1510. X\tENDOFARGS\n\
  1511. X";
  1512. X
  1513. Xstatic char word_str[] = "HELP (print help and quit)";
  1514. X
  1515. Xmain()
  1516. X#ifdef __ANSI_C__
  1517. X#endif
  1518. X{
  1519. X   char **vector;
  1520. X   unsigned i, numtoks;
  1521. X
  1522. X   printf( "test of strtrim() and strsplit():\n\n" );
  1523. X
  1524. X   printf( "unparsed string='%s'\n", string2 );
  1525. X   printf( "ltrimmed string='%s'\n", strltrim( string2, WS ) );
  1526. X   printf( "rtrimmed string='%s'\n", strrtrim( string2, WS ) );
  1527. X
  1528. X   numtoks = strsplit( &vector, string, "," );
  1529. X   printf( "number of tokens=%d\n", numtoks );
  1530. X   for ( i = 0 ; i < numtoks ; i++ ) {
  1531. X      printf( "trimmed token[%d] = '%s'\n", i, strtrim( vector[i], WS ) );
  1532. X   }
  1533. X
  1534. X#ifdef vms
  1535. X   exit( SS$_NORMAL );
  1536. X#else
  1537. X   exit( 0 );
  1538. X#endif
  1539. X
  1540. X}
  1541. X
  1542. X#endif
  1543. END_OF_FILE
  1544. if test 40645 -ne `wc -c <'strfuncs.c'`; then
  1545.     echo shar: \"'strfuncs.c'\" unpacked with wrong size!
  1546. fi
  1547. # end of 'strfuncs.c'
  1548. fi
  1549. echo shar: End of archive 7 \(of 10\).
  1550. cp /dev/null ark7isdone
  1551. MISSING=""
  1552. for I in 1 2 3 4 5 6 7 8 9 10 ; do
  1553.     if test ! -f ark${I}isdone ; then
  1554.     MISSING="${MISSING} ${I}"
  1555.     fi
  1556. done
  1557. if test "${MISSING}" = "" ; then
  1558.     echo You have unpacked all 10 archives.
  1559.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1560. else
  1561.     echo You still need to unpack the following archives:
  1562.     echo "        " ${MISSING}
  1563. fi
  1564. ##  End of shell archive.
  1565. exit 0
  1566.  
  1567. exit 0 # Just in case...
  1568.