home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cmdline.lha / cmdline / src / lib / strindent.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-03  |  8.6 KB  |  312 lines

  1. //-------------------------------------------------------------------------
  2. // ^FILE: strindent.c - implement the strindent() function
  3. //
  4. // ^DESCRIPTION:
  5. //    This file implements the function strmatch() which matches a 
  6. //    keyword (case insensitive) and the function strindent() which
  7. //    prints a hanging, indented paragraph.
  8. //
  9. //    On VMS systems - we also implement a replacement for "getenv()"
  10. //    named "getsym()" to get the value of a VMS symbol.
  11. //
  12. // ^HISTORY:
  13. //    12/05/91     Brad Appleton     <brad@ssd.csd.harris.com>     Created
  14. //-^^-----------------------------------------------------------------------
  15.  
  16. #include <iostream.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19.  
  20. #include "cmdline.h"
  21.  
  22. // Need a portable version of tolower
  23. //
  24. //   NOTE:: I would make this inline except that cfront refuses
  25. //          to inline it because it is used twice in expressions
  26. //
  27. #define TO_LOWER(c)  ((isupper(c)) ? tolower(c) : c)
  28.  
  29.  
  30. //-------
  31. // ^FUNCTION: strmatch - match a keyword
  32. //
  33. // ^SYNOPSIS:
  34. //    static CmdLine::strmatch_t CmdLine::strmatch(src, attempt, len);
  35. //
  36. // ^PARAMETERS:
  37. //    const char * src;
  38. //    -- the actual keyword to match against
  39. //
  40. //    const char * attempt;
  41. //    -- the "candidate" that may or may not match the keyword
  42. //
  43. //    unsigned len;
  44. //    -- the number of character of "attempt" to consider (==0 if all
  45. //       characters of "attempt" should be used).
  46. //
  47. // ^DESCRIPTION:
  48. //    See if "attempt" matches "src" (either partially or completely) and
  49. //    return the result.
  50. //
  51. // ^REQUIREMENTS:
  52. //    None that havent been discusses in the PARAMETERS section.
  53. //
  54. // ^SIDE-EFFECTS:
  55. //    None.
  56. //
  57. // ^RETURN-VALUE:
  58. //    str_EXACT if "attempt" completely matches "src"
  59. //    str_PARTIAL is "attempt" partially matches "src"
  60. //    str_NONE otherwise
  61. //
  62. // ^ALGORITHM:
  63. //    For each character (in order) of "attempt" to be considered
  64. //       if attempt[i] != src[i] (case insensitive) return str_NONE
  65. //    end-for
  66. //    if we have exhausted "src" return str_EXACT,
  67. //    else return str_PARTIAL
  68. //-^^----
  69. CmdLine::strmatch_t
  70. CmdLine::strmatch(const char * src, const char * attempt, unsigned len)
  71. {
  72.    unsigned  i;
  73.  
  74.    if (src == attempt)  return  str_EXACT ;
  75.    if ((src == NULL) || (attempt == NULL))  return  str_NONE ;
  76.    if ((! *src) && (! *attempt))  return  str_EXACT ;
  77.    if ((! *src) || (! *attempt))  return  str_NONE ;
  78.  
  79.    for (i = 0 ; ((i < len) || (! len)) && (attempt[i] != '\0') ; i++) {
  80.       if (TO_LOWER(src[i]) != TO_LOWER(attempt[i]))  return  str_NONE ;
  81.    }
  82.  
  83.    return  (src[i] == '\0') ? str_EXACT : str_PARTIAL ;
  84. }
  85.  
  86.  
  87. //--------------------------------------------------------------------------
  88. // ^FUNCTION: strindent - print a hanging indented paragraph
  89. //
  90. // ^SYNOPSIS:
  91. //    void CmdLine::strindent(os, maxcols, margin, title, indent, text)
  92. //
  93. // ^PARAMETERS:
  94. //    ostream & os;
  95. //    -- the stream to which output is sent
  96. //
  97. //    unsigned maxcols;
  98. //    -- the maximum width (in characters) of the output
  99. //
  100. //    unsigned margin;
  101. //    -- the number of spaces to use as the left margin
  102. //
  103. //    char * title;
  104. //    -- the paragraph title
  105. //
  106. //    unsigned indent;
  107. //    -- the distance between the title and the paragraph body
  108. //
  109. //    char * text;
  110. //    -- the body of the paragraph
  111. //
  112. // ^DESCRIPTION:
  113. //    Strindent will print on os, a titled, indented paragraph as follows:
  114. //
  115. //    <----------------------- maxcols --------------------------->
  116. //    <--- margin --><----- indent ---->
  117. //                   title              This is the first sentence
  118. //                                      of the paragraph. Etc ...
  119. //
  120. // ^REQUIREMENTS:
  121. //    - maxcols and indent must be positive numbers with maxcols > indent.
  122. //    - title should NOT contain any tabs or newlines.
  123. //
  124. // ^SIDE-EFFECTS:
  125. //    Output is printed to os.
  126. //
  127. // ^RETURN-VALUE:
  128. //    None.
  129. //
  130. // ^ALGORITHM:
  131. //    Print the paragraph title and then print the text.
  132. //    Lines are automatically adjusted so that each one starts in the
  133. //    appropriate column.
  134. //-^^-----------------------------------------------------------------------
  135. void
  136. CmdLine::strindent(ostream    & os,
  137.                    unsigned     maxcols,
  138.                    unsigned     margin,
  139.                    const char * title,
  140.                    unsigned     indent,
  141.                    const char * text)
  142. {
  143.    // If we were given non-sensical parameters then dont use them
  144.    if (margin > maxcols)  margin = 0;
  145.    if ((indent + margin) >= maxcols)  indent = 1;
  146.  
  147.    // print the title (left-justified)
  148.    os.width(margin);
  149.    os << "" ;
  150.    long  save_flags = os.flags();
  151.    os.setf(ios::left, ios::adjustfield);
  152.    os.width(indent);
  153.    os << ((title) ? title : "");
  154.    os.flags(save_flags);
  155.  
  156.    if (text == NULL) {
  157.       os << endl ;
  158.       return;
  159.    }
  160.  
  161.    // If the title is too big, start the paragraph on a new line
  162.    if (title  &&  (::strlen(title) > indent)) {
  163.       os << endl ;
  164.       os.width(margin + indent);
  165.       os << "";
  166.    }
  167.  
  168.    // Loop through the paragraph text witing to print until we absolutely
  169.    // have to.
  170.    //
  171.    unsigned  col = margin + indent + 1;
  172.    unsigned  index = 0 ;
  173.    unsigned  last_white = 0 ;
  174.    const char * p = text ;
  175.  
  176.    while (p[index]) {
  177.       switch (p[index]) {
  178.          // If we have a space - just remember where it is
  179.       case ' ' :
  180.          last_white = index;
  181.          ++col;
  182.          ++index;
  183.          break;
  184.  
  185.          // If we have a tab - remember where it is and assume it
  186.          // will take up 8 spaces in the output.
  187.          //
  188.       case '\t' :
  189.          last_white = index;
  190.          col += 8;
  191.          ++index;
  192.          break;
  193.  
  194.          // If we have a form-feed, carriage-return, or newline, then
  195.          // print what we have so far (including this character) and
  196.          // start a new line.
  197.          //
  198.       case '\n' :
  199.       case '\r' :
  200.       case '\f' :
  201.          os.write(p, index + 1);
  202.          p += index + 1;
  203.          col = margin + indent + 1;
  204.          index = last_white = 0;
  205.          if (*p) {
  206.             os.width(margin + indent);
  207.             os << "";
  208.          }
  209.          break;
  210.  
  211.       default:
  212.          ++col;
  213.          ++index;
  214.          break;
  215.       } //switch
  216.  
  217.          // Are we forced to start a new line?
  218.       if (col > maxcols) {
  219.             // Yes - if possible, print upto the last whitespace character
  220.             //       and start the next line on a word-boundary
  221.          if (last_white) {
  222.             os.write(p, last_white);
  223.             p += last_white;
  224.             while (*p == ' ')  ++p;
  225.          } else {
  226.                // No word boundary in sight - just split the line here!
  227.             os.write(p, index);
  228.             p += index;
  229.          }
  230.          os << endl ;
  231.  
  232.             // We just printed a newline - dont print another one right now
  233.          while ((*p == '\n') || (*p == '\r') || (*p == '\f'))  ++p;
  234.          col = margin + indent + 1;
  235.          index = last_white = 0;
  236.          if (*p) {
  237.             os.width(margin + indent);
  238.             os << "";
  239.          }
  240.       } else if (index && (! p[index])) {
  241.          os << p << endl ;
  242.       }
  243.    } //while
  244. }
  245.  
  246.  
  247. #ifdef vms
  248.  
  249. #  include <descrip.h>
  250. #  include <libdef.h>
  251.  
  252.    extern "C" {
  253.       long   lib$get_symbol(...);
  254.       void   exit(int);
  255.    }
  256.  
  257. //----------------------
  258. // ^FUNCTION: getsym - retrieve the value of a VMS symbol
  259. //
  260. // ^SYNOPSIS:
  261. //    const char * getsym(sym_name)
  262. //
  263. // ^PARAMETERS:
  264. //    char * sym_name;
  265. //    -- name of the symbol to retrieve
  266. //
  267. // ^DESCRIPTION:
  268. //    Get_symbol will lookup the named symbol and return its value
  269. //    as a string.
  270. //
  271. // ^REQUIREMENTS:
  272. //    sym_name should correspond to the name of a pre-defined symbol.
  273. //
  274. // ^SIDE-EFFECTS:
  275. //    None.  NO storage is allocated for the symbol-value and it will
  276. //    be overwritten by the next call to this function.
  277. //
  278. // ^RETURN-VALUE:
  279. //    NULL if the symbol is not found, otherwise it returns a pointer
  280. //    to a static buffer containing the contents of the symbol value.
  281. //    You MUST be finished using this buffer before another call to
  282. //    get_symbol is made.
  283. //
  284. // ^ACKNOWLEDGEMENTS:
  285. //    Thanx to Jim Barbour for writing most of this code. --BDA
  286. //
  287. // ^ALGORITHM:
  288. //    Trivial - just use the LIB$GET_SYMBOL system service.
  289. //-^^-------------------
  290. const char *
  291. getsym(const char * sym_name)
  292. {
  293.    static  char  sym_value[256];
  294.    unsigned long   stat;
  295.    unsigned short  buflen;
  296.    $DESCRIPTOR(sym_name_d, sym_name);
  297.    $DESCRIPTOR(sym_value_d, sym_value);
  298.  
  299.    sym_value_d.dsc$w_length = sizeof(sym_value);
  300.    sym_name_d.dsc$w_length = ::strlen(sym_name);
  301.    stat = lib$get_symbol(&sym_name_d, &sym_value_d, &buflen, (void *)0);
  302.    if (stat == LIB$_NOSUCHSYM) {
  303.       return  NULL;
  304.    } else if (! (stat & 1)) {
  305.       ::exit(stat);
  306.    }
  307.    sym_value[buflen] = '\0';
  308.    return  sym_value;
  309. }
  310.  
  311. #endif  /* vms */
  312.