/* makstr.f -- translated by f2c (version 19980913). You must link the resulting object file with the libraries: -lf2c -lm (in that order) */ #include "f2c.h" /* $Procedure MAKSTR (Make String ) */ /* Subroutine */ int makstr_0_(int n__, char *pattrn, char *this__, char * next, ftnlen pattrn_len, ftnlen this_len, ftnlen next_len) { /* System generated locals */ integer i__1, i__2; /* Builtin functions */ /* Subroutine */ int s_copy(char *, char *, ftnlen, ftnlen); integer i_len(char *, ftnlen); /* Local variables */ logical keep; integer i__, j, k; extern /* Subroutine */ int chkin_(char *, ftnlen); extern integer rtrim_(char *, ftnlen); extern /* Subroutine */ int sigerr_(char *, ftnlen), chkout_(char *, ftnlen), setmsg_(char *, ftnlen); integer min__, max__; /* $ Abstract */ /* Make a string matching a pattern. This routine serves as an */ /* umbrella routine for the two entry points FSTSTR and NXTSTR. */ /* $ Required_Reading */ /* None. */ /* $ Keywords */ /* Utility */ /* $ Declarations */ /* $ Brief_I/O */ /* VARIABLE I/O DESCRIPTION */ /* -------- --- -------------------------------------------------- */ /* PATTRN I FSTSTR, NXTSTR */ /* THIS I NXTSTR */ /* NEXT O FSTSTR, NXSTR */ /* $ Detailed_Input */ /* PATTRN is a string that specifies a pattern that all strings */ /* in a sequence must match. There are several special */ /* substrings in PATTRN that must be recognized. */ /* 1) A substring of the form '<*>' (where * is used */ /* as a variable length wildcard character) is called */ /* an expansion. The substring that occurs between */ /* the angle brackets < > is called the invisible */ /* portion of the expansion. When the tokens of */ /* PATTRN are counted the invisible portion of the */ /* expansion is not counted. Thus an expansion has */ /* exactly two tokens '<' and '>' The invisible */ /* portion of the expansion must not contain */ /* any of the characters '<', '>', '{', or '}'. */ /* 2) A substring of the form '{#-$}' where # and $ */ /* stand for any chacter from the set */ /* '0', ... , '9', 'a', ... , 'z' is called a */ /* restriction. */ /* A pattern may consist of any collection of */ /* characters. However, the characters '<' and */ /* '>' must always occur in balanced pairs with '<' */ /* on the left and '>' on the right. Moreover, they */ /* cannot be nested even if they are balanced. Similary */ /* '{' and '}' must always appear as a balanced pair */ /* and have exactly 3 characters between them. The */ /* first is a lower case letter or a digit. The second */ /* letter may be anything (usually a hyphen, colon or */ /* comma). The third character must */ /* also be a letter between 0, ... ,9, a, b, ... , z */ /* and must occur later in the collating sequence than */ /* the first letter in the triple that occurs between */ /* '{' and '}'. */ /* For example the following are valid patterns */ /* PAT__{0-9}{a-z}{a-d} */ /* COUNTER{0-9}{0-9}{0-9}{0-9} */ /* COUNTER{0:9}{0,9}{a;b} */ /* but the following are not */ /* PAT_<<>>_{0-9}{a-z}{a-d} --- Nested < > */ /* COUNTER{9-0} --- 9 before 0 */ /* PAT_{0to0} --- 4 characters between{} */ /* PAT_{A-Z} --- uppercase letters in{} */ /* PAT_{+-$} --- bad characters in {} */ /* Pattern should be viewed as consisting of a sequence */ /* of tokens. The tokens consist of characters that */ /* are not part of an expansion or restriction */ /* restrictions and the '<' and '>' characters of */ /* any expansion. */ /* THIS is a string that should be incremented to get the */ /* NEXT string that matches the pattern. */ /* Note THIS must match the input pattern. */ /* The tokens of THIS are the characters upto and */ /* including the last non-blank character of THIS. */ /* This should have the same number of tokens as does */ /* PATTRN. */ /* Suppose that TOKTHS (I) is the I'th token of THIS */ /* and that TOKPAT(I) is the I'th token of PATTRN. */ /* If TOKPAT(I) is a restriction then TOKTHS(I) must */ /* be one of the characters belonging to the range */ /* of the restriction. */ /* Otherwise TOKPAT(I) and TOKTHS(I) match. */ /* Thus the pattern */ /* 'XXX{0-9}{0-z}' */ /* Matches */ /* 'THIS_5a' */ /* This kind of matching is of course a bit */ /* confusing. It is probably more useful to */ /* have THIS take all of its tokens to be identical */ /* to the character tokens of of PATTRN and match */ /* the restriction tokens in all other cases. */ /* In particular, the routine FSTSTR, will take */ /* PATTRN as an input and produce the a first */ /* string in the sequence of strings that matches */ /* PATTRN by simply copying the character tokens */ /* of PATTRN to the output string and taking the */ /* lower bound of the restrictions of PATTRN */ /* to get the matching tokens for each restriction. */ /* See FSTSTR for a more complete discussion. */ /* $ Detailed_Output */ /* NEXT See the entry points FSTSTR and NXTSTR */ /* $ Parameters */ /* None. */ /* $ Files */ /* None. */ /* $ Exceptions */ /* Error free. */ /* $ Particulars */ /* This is a rather immature routine that can assist with the */ /* problem of constructing a sequence of character strings. */ /* This routine was written as a support routine for the */ /* SPICE program CHRISTEN and the routine NOMEN. As such */ /* it was possible to ensure that all of the detailed conditions */ /* of PATTRN and THIS were met by the routines that call this. */ /* However, this routine can prove useful in other contexts and */ /* is provided so that you can easily produce a large sequence of */ /* non-repeating character strings. But YOU MUST BE CAREFUL */ /* WITH YOUR USE OF THIS ROUTINE. Unlike most SPICE routines */ /* there is no exception handling done. If you pass in a bad PATTRN */ /* or value for THIS that does not match PATTRN the result are */ /* of this routine are unpredictable. The routine will certainly */ /* not diagnose the problem and can possibly cause your program */ /* to crash with no diagnostics to help with finding the problem. */ /* If you simply need to produce a sequence of strings, you */ /* should probably avoid putting expansions ( substrings like */ /* ) in your input pattern. These are special */ /* strings that support the tasks needed by NOMEN and CHRISTEN. */ /* Stick to simple patterns such as the one shown here: */ /* PATTRN = 'base{0-z}{0-z}{0-z}{0-z}.tmp' */ /* THIS = 'base0000.tmp' */ /* For creating file names or unique non-frequently repeating */ /* strings, this will probably do the job. */ /* Note that upper case letters are not supported in PATTRNs, this */ /* is a UNIX-ish restriction (most file names are written in */ /* lower case in UNIX). This routine could be easily modified */ /* to support a wider range of characters. Or if you want all */ /* uppercase characters, apply the SPICE routine UPPER to NEXT */ /* when you get back from your call to NXTSTR. */ /* Still even with all the restrictions and lack of exception */ /* handling this does solve a basic problem of creating an */ /* increasing sequence of character strings and saves you */ /* from the task of figuring out the details (in particular */ /* how to cascade up the string when you have many letters */ /* to change to get to the next string). */ /* The most common useage is to use FSTSTR to get a first string */ /* in a sequence that matches PATTRN and then to call NXTSTR */ /* to produce subsequent matching strings. */ /* $ Examples */ /* See the inividiual entry points. */ /* $ Restrictions */ /* There are lots of restrictions. See the detailed input */ /* and particulars for all the warnings. */ /* $ Author_and_Institution */ /* W.L. Taber (JPL) */ /* $ Literature_References */ /* None. */ /* $ Version */ /* - Support Version 1.1.0, 18-JUN-1999 (WLT) */ /* Placed a RETURN statement before the first entry point */ /* to protect against the coding error of calling the */ /* subroutine MAKSTR directly. */ /* - Command Loop Configured Version 1.0.0, 3-MAY-1994 (WLT) */ /* This is the configured version of the Command Loop */ /* software as of May 4, 1994 */ /* - Prototype Version 1.0.0, 16-APR-1994 (WLT) */ /* -& */ /* Spicelib functions */ /* Local Varialbes */ switch(n__) { case 1: goto L_fststr; case 2: goto L_nxtstr; } return 0; /* $Procedure FSTSTR ( First string matching a pattern ) */ L_fststr: /* $ Abstract */ /* Given a naming pattern, this routine produces the first */ /* legal name implied by the pattern. */ /* $ Required_Reading */ /* None. */ /* $ Keywords */ /* UTILITY */ /* $ Declarations */ /* IMPLICIT NONE */ /* CHARACTER*(*) PATTRN */ /* CHARACTER*(*) NEXT */ /* $ Brief_I/O */ /* VARIABLE I/O DESCRIPTION */ /* -------- --- -------------------------------------------------- */ /* PATTRN I A pattern to use when constructing strings */ /* NEXT O The first pattern that fits the input pattern */ /* $ Detailed_Input */ /* PATTRN is a pattern from which NEXT will be constructed. */ /* See the discussion of PATTRN in the umbrella routine */ /* for more details. */ /* $ Detailed_Output */ /* NEXT is the first string in the ASCII collating sequence */ /* that matches pattern. The tokens of NEXT are the */ /* characters up to the last non-blank character. The */ /* number of tokens in NEXT and PATTRN are the same. */ /* Moreover, the tokens of NEXT are constructed from */ /* PATTRN from the following rule: */ /* If TOKEN(I) is the I'th token of PATTRN and */ /* it is not a restriction (i.e. it's a single letter) */ /* then the I'th token of NEXT is TOKEN(I). */ /* If TOKEN(I) is the I'th token of PATTRN and it */ /* is a restriction then the I'th token of NEXT is */ /* the character of the restriction that follows */ /* the left brace '{' of the restriction. */ /* In particular this means that expansions are copied */ /* into NEXT as simply '<>'. */ /* $ Parameters */ /* None. */ /* $ Files */ /* None. */ /* $ Exceptions */ /* 1) If the output string is not long enough to hold the */ /* first string that matches PATTRN the error */ /* SPICE(OUTPUTTOOLONG) will be signalled. */ /* $ Particulars */ /* This is a rather immature routine that is used by Christen for */ /* generating the first string in a sequence of strings specified */ /* by a naming convention. There are plenty of things that could */ /* go wrong if the input PATTRN is not well formed or if there */ /* is not room in NEXT to hold the string that should be */ /* constructed by this routine. However, none of these problems */ /* are checked for or diagnosed. */ /* Nevertheless, this routine may prove useful in many contexts */ /* where you need to create a sequence of names and simply want */ /* to start with a pattern and let software handle the rest for */ /* you. */ /* Normal usage would be to use FSTSTR to get the first string */ /* of a set specified by a string pattern and to then generate */ /* the rest using the routine NXTSTR. This can be useful in those */ /* situations where you need to create a new file and don't want */ /* to overwrite any existing file. */ /* If you plan to make use of this routine in conjuction with */ /* NXTSTR you should be sure to read the discussion of NXTSTR */ /* that appears in the header to that routine. */ /* $ Examples */ /* Suppose that you want to be able to create a file name */ /* that can be used as a scratch area for some aspect of your */ /* program. You can use this routine in conjuction with NXTSTR */ /* to generate a name of a NEW file for this purpose. */ /* PATTRN = 'file{0-z}{0-z}{0-z}{0-z}.tmp' */ /* CALL FSTSTR ( PATTRN, NAME ) */ /* DO WHILE ( EXISTS(NAME) ) */ /* THIS = NAME */ /* CALL NXTSTR ( PATTRN, THIS, NAME ) */ /* END DO */ /* CALL TXTOPN ( NAME, UNIT ) */ /* $ Restrictions */ /* There are lots of restrictions associated with PATTRN and */ /* NEXT that are discussed above. This routine doesn't perform */ /* any error checking so you need to be sure that the inputs */ /* are properly specified before you call this routine. */ /* $ Author_and_Institution */ /* W.L. Taber (JPL) */ /* $ Literature_References */ /* None. */ /* $ Version */ /* - Support Version 1.1.0, 18-JUN-1999 (WLT) */ /* Placed a RETURN statement before the first entry point */ /* to protect against the coding error of calling the */ /* subroutine MAKSTR directly. */ /* - Command Loop Configured Version 1.0.0, 3-MAY-1994 (WLT) */ /* This is the configured version of the Command Loop */ /* software as of May 4, 1994 */ /* - Prototype Version 1.0.0, 17-APR-1994 (WLT) */ /* -& */ /* $ Index_Entries */ /* Get the first name in a sequence that matches a pattern */ /* -& */ /* There are two things to handle: */ /* balanced brackets: <> */ /* balanced braces: {} */ /* We do this in one pass. */ s_copy(next, " ", next_len, (ftnlen)1); keep = TRUE_; j = 1; i__1 = rtrim_(pattrn, pattrn_len); for (i__ = 1; i__ <= i__1; ++i__) { if (*(unsigned char *)&pattrn[i__ - 1] == '>') { keep = TRUE_; } if (*(unsigned char *)&pattrn[i__ - 1] == '{') { i__2 = i__; s_copy(next + (j - 1), pattrn + i__2, (ftnlen)1, i__ + 1 - i__2); ++j; keep = FALSE_; } if (keep) { *(unsigned char *)&next[j - 1] = *(unsigned char *)&pattrn[i__ - 1]; ++j; } if (*(unsigned char *)&pattrn[i__ - 1] == '<') { keep = FALSE_; } if (*(unsigned char *)&pattrn[i__ - 1] == '}') { keep = TRUE_; } if (j > i_len(next, next_len)) { chkin_("FSTSTR", (ftnlen)6); setmsg_("The string provided for the first name is too short for" " the input pattern. ", (ftnlen)75); sigerr_("SPICE(OUTPUTTOOLONG)", (ftnlen)20); chkout_("FSTSTR", (ftnlen)6); } } return 0; /* $Procedure NXTSTR (Next String) */ L_nxtstr: /* $ Abstract */ /* Given a pattern for incrementing a string and a current */ /* string value (that fits the pattern) produce the next */ /* string in the sequence. */ /* $ Required_Reading */ /* None. */ /* $ Keywords */ /* UTILITY */ /* $ Declarations */ /* IMPLICIT NONE */ /* CHARACTER*(*) PATTRN */ /* CHARACTER*(*) THIS */ /* CHARACTER*(*) NEXT */ /* $ Brief_I/O */ /* VARIABLE I/O DESCRIPTION */ /* -------- --- -------------------------------------------------- */ /* PATTRN I a pattern to use to get NEXT from THIS */ /* THIS I is a string that matches PATTRN */ /* NEXT O is the first string after THIS to match PATTRN */ /* $ Detailed_Input */ /* PATTRN is a string that specifies a pattern that all strings */ /* in a sequence must match. See the discussion of */ /* PATTRN in the umbrella routine for more details. */ /* THIS is a string that should be incremented to get the */ /* NEXT string that matches the pattern. */ /* Note THIS must match the input pattern. */ /* The tokens of THIS are the characters upto and */ /* including the last non-blank character of THIS. */ /* This should have the same number of tokens as does */ /* PATTRN. */ /* Suppose that TOKTHS (I) is the I'th token of THIS */ /* and that TOKPAT(I) is the I'th token of PATTRN. */ /* If TOKPAT(I) is a restriction then TOKTHS(I) must */ /* be one of the characters belonging to the range */ /* of the restriction. */ /* Otherwise TOKPAT(I) and TOKTHS(I) match. */ /* Thus the pattern */ /* 'XXX{0-9}{0-z}' */ /* Matches */ /* 'THIS_5a' */ /* This kind of matching is of course a bit */ /* confusing. It is probably more useful to */ /* have THIS take all of its tokens to be identical */ /* to the character tokens of of PATTRN and match */ /* the restriction tokens in all other cases. */ /* In particular, the routine FSTSTR, will take */ /* PATTRN as an input and produce the a first */ /* string in the sequence of strings that matches */ /* PATTRN by simply copying the character tokens */ /* of PATTRN to the output string and taking the */ /* lower bound of the restrictions of PATTRN */ /* to get the matching tokens for each restriction. */ /* See FSTSTR for a more complete discussion. */ /* $ Detailed_Output */ /* NEXT is the next string in the ascii collating */ /* sequence that matches PATTRN and is equal to */ /* THIS on the non-restriction matching letters */ /* of THIS. There is one exception to this rule. */ /* If there is no such string, (i.e. THIS is the */ /* last string that can be produced that matches */ /* PATTRN) then NEXT will be the first string */ /* that matches PATTRN and is equal to THIS on the */ /* non-restriction matching letters of THIS. */ /* If PATTRN contains no restrictions, then NEXT */ /* will equal THIS. */ /* $ Parameters */ /* None. */ /* $ Files */ /* None. */ /* $ Exceptions */ /* Error free. */ /* $ Particulars */ /* This is a rather immature routine that can assist with the */ /* problem of constructing a sequence of character strings. */ /* This routine was written as a support routine for the */ /* SPICE program CHRISTEN and the routine NOMEN. As such */ /* it was possible to ensure that all of the detailed conditions */ /* of PATTRN and THIS were met by the routines that call this. */ /* However, this routine can prove useful in other contexts and */ /* is provided so that you can easily produce a large sequence of */ /* non-repeating character strings. But YOU MUST BE CAREFUL */ /* WITH YOUR USE OF THIS ROUTINE. Unlike most SPICE routines */ /* there is no exception handling done. If you pass in a bad PATTRN */ /* or value for THIS that does not match PATTRN the result are */ /* of this routine are unpredictable. The routine will certainly */ /* not diagnose the problem and can possibly cause your program */ /* to crash with no diagnostics to help with finding the problem. */ /* If you simply need to produce a sequence of strings, you */ /* should probably avoid putting expansions ( substrings like */ /* ) in your input pattern. These are special */ /* strings that support the tasks needed by NOMEN and CHRISTEN. */ /* Stick to simple patterns such as the one shown here: */ /* PATTRN = 'base{0-z}{0-z}{0-z}{0-z}.tmp' */ /* THIS = 'base0000.tmp' */ /* For creating file names or unique non-frequently repeating */ /* strings, this will probably do the job. */ /* Note that upper case letters are not supported in PATTRNs, this */ /* is a UNIX-ish restriction (most file names are written in */ /* lower case in UNIX). This routine could be easily modified */ /* to support a wider range of characters. Or if you want all */ /* uppercase characters, apply the SPICE routine UPPER to NEXT */ /* when you get back from your call to NXTSTR. */ /* Still even with all the restrictions and lack of exception */ /* handling this does solve a basic problem of creating an */ /* increasing sequence of character strings and saves you */ /* from the task of figuring out the details (in particular */ /* how to cascade up the string when you have many letters */ /* to change to get to the next string). */ /* $ Examples */ /* Suppose you wanted to create the sequence of strings that */ /* give the times on a 24 hour clock. I.e 00:00:00, 00:00:01, ... */ /* 23:59:59. This routine is ideally suited to this task. */ /* PATTRN = {0-2}{0-9}:{0-5}{0-9}:{0-5}{0-9} */ /* START = '29:59:59' */ /* LAST = '23:59:59' */ /* THIS = START */ /* DO WHILE ( NEXT .NE. LAST ) */ /* CALL NXTSTR ( PATTRN, THIS, NEXT ) */ /* WRITE (*,*) NEXT */ /* THIS = NEXT */ /* END DO */ /* The output of the routine would be: */ /* 00:00:00 */ /* 00:00:01 */ /* 00:00:02 */ /* . */ /* . */ /* . */ /* 23:59:57 */ /* 23:59:58 */ /* 23:59:59 */ /* $ Restrictions */ /* There are lots of restrictions. See the detailed input */ /* and particulars for all the warnings. */ /* $ Author_and_Institution */ /* W.L. Taber (JPL) */ /* $ Literature_References */ /* None. */ /* $ Version */ /* - Support Version 1.1.0, 18-JUN-1999 (WLT) */ /* Placed a RETURN statement before the first entry point */ /* to protect against the coding error of calling the */ /* subroutine MAKSTR directly. */ /* - Command Loop Configured Version 1.0.0, 3-MAY-1994 (WLT) */ /* This is the configured version of the Command Loop */ /* software as of May 4, 1994 */ /* - Prototype Version 1.0.0, 16-APR-1994 (WLT) */ /* -& */ /* $ Index_Entries */ /* Construct a non-repeating increasing sequence of strings */ /* -& */ /* First copy THIS into NEXT and find the ends of PATTRN and NEXT. */ s_copy(next, this__, next_len, this_len); j = rtrim_(pattrn, pattrn_len); i__ = rtrim_(next, next_len); /* We work backwards from the right end of the string. */ while(j > 0) { /* If the current character is a right brace we are going */ /* to assume we are at the end of a restriction token. Use */ /* the range of the restriction and the current character */ /* of NEXT to determine the "next" character and whether or */ /* not we can quit now. */ if (*(unsigned char *)&pattrn[j - 1] == '}') { i__1 = j - 2; max__ = *(unsigned char *)&pattrn[i__1]; i__1 = j - 4; min__ = *(unsigned char *)&pattrn[i__1]; k = *(unsigned char *)&next[i__ - 1] + 1; if (k > max__) { /* Roll over the characters, We aren't done we */ /* need to keep stepping back through the string */ *(unsigned char *)&next[i__ - 1] = (char) min__; } else if (k > '9' && k < 'a') { /* By convention, the first character following '9' is 'a'. */ /* Since we don't need to "roll over" this character we */ /* are done at this point. */ *(unsigned char *)&next[i__ - 1] = 'a'; return 0; } else { /* We didn't need to roll over the character so we just */ /* put in the new one and we can quit now. */ *(unsigned char *)&next[i__ - 1] = (char) k; return 0; } /* perform the arithmetic needed if we had to roll over the */ /* character. */ j += -5; --i__; /* If the character is '>' we assume we are at the right end */ /* of an expansion. */ } else if (*(unsigned char *)&pattrn[j - 1] == '>') { /* Skip over the invisible portion of the expansion. */ while(*(unsigned char *)&pattrn[j - 1] != '<') { --j; } --i__; } else { /* Nothing to do, just back up to the character to the */ /* left of the current character. */ --j; --i__; } } return 0; } /* makstr_ */ /* Subroutine */ int makstr_(char *pattrn, char *this__, char *next, ftnlen pattrn_len, ftnlen this_len, ftnlen next_len) { return makstr_0_(0, pattrn, this__, next, pattrn_len, this_len, next_len); } /* Subroutine */ int fststr_(char *pattrn, char *next, ftnlen pattrn_len, ftnlen next_len) { return makstr_0_(1, pattrn, (char *)0, next, pattrn_len, (ftnint)0, next_len); } /* Subroutine */ int nxtstr_(char *pattrn, char *this__, char *next, ftnlen pattrn_len, ftnlen this_len, ftnlen next_len) { return makstr_0_(2, pattrn, this__, next, pattrn_len, this_len, next_len); }