home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / C / GET_IT.ZIP / GET.DOC < prev    next >
Encoding:
Text File  |  1988-02-10  |  12.0 KB  |  243 lines

  1.    This program and documentation was typed from Micro Cornucopia magazine
  2. and is authored by Jack Purdum. It is from the March/April 1988, No. 40
  3. issue and is on page 20. The title of the article is "PROGRAMMING FOR CHANGE:
  4. Using Data Files In Lieu Of Program Data". See the file READ.GET in this 
  5. archive for some descrepencies I found. The text from the magazine follows:
  6. *******************************************************************************
  7.  
  8.    I guess I'm pretty lucky: my family has progressed from tolerating my
  9. computer activities to participating in them. My wife does most of her reports 
  10. and my daughter does her homework on my system. That's the good part.
  11.    On the down side, I really don't want them playing around with the stuff
  12. I'm working on, even accidentally. So I created a directory for each of them 
  13. to use. That's where the problem begins.
  14.  
  15. THE PROBLEM
  16.    My hard disk has a directory structure that's confusing to anyone,including 
  17. myself. One of these days, of course, I'm going to get organized. But in the 
  18. meantime, I shouldn't be too surprised that neither wife nor daughter are 
  19. excited about learning how neat the MS-DOS hierarchical directouy structure 
  20. is.
  21.    We programmers, in general, assume it's obvious to everyone (including non-
  22. programmers) how to move between directories on a hard disk. Not so. Although 
  23. learning to run a word processor was easy enough for my family, getting to the 
  24. correct directory was a boggle, confusing. I kept telling them how easy it 
  25. was: all they had to remember was to type:
  26. D:
  27. cd\family\words\name
  28.  
  29. where name is either Karol or Katie.
  30.    In their defense, I'll admit there is an incredible number of combinations
  31. in the above sequence. What the problem called for was a programming solution: 
  32. a tool to simplify moving among directories.
  33.    The more I thought about it, the more I was convinced I wouldn't mind an
  34. easier way to move between directories and subdirectories myself. Maybe I 
  35. COULD get organized.
  36.    It's not uncommon for me to have a pathname something like:
  37.  
  38. C:\eco88\tools\source\project1
  39.  
  40.    I know i'm working on project1, but I'm not always sure which subdirect-
  41. ory holds it. Also, it's a hassle to type in the pathname for project1. Yet, I 
  42. don't want to move the project from its (logical?) place.
  43.  
  44. DESIGNING A SOLUTION
  45.    When I first started thinking about how to address the problem, several
  46. solutions seemed feasible. The most direct is a batch file for each user that 
  47. contains the sequence of MS-DOS commands that would place the user in the 
  48. proper directory. That's the easiest solution.
  49.    It would solve my family's immediate problem, but we'd need a batch file
  50. for each directory pathname we wanted to use. Again some form of program 
  51. seemed to be the answer.
  52.    First, what information does MS-DOS need to chamge directories ?
  53.    MS-DOS needs to know only two things: 1) the full pathname, and 2) possibly
  54. a drive name. Given what I wanted to do, I needed a third piece of 
  55. information, an abbreviation for the full pathname, as well. For the 
  56. pathname mentioned earlier, the information might be:
  57. (1)\eco88\tools\source\project1
  58. (2)C:
  59. (3)project1
  60.  
  61.    Therefore, if I type in "project1" from any directory on any drive in my
  62. system, I should end up in the directory C:\eco88\tools\source\project1.
  63.    Second, how can I access the program from anywhere on the disk ?
  64.    Most programmers are familiar with the "environment" area available in
  65. MS-DOS. It's a small area of memory that MS-DOS can examine for information to 
  66. be used with MS-DOS commands. Of interest to us is the PATH command which 
  67. tells MS-DOS which pathnames to search if a file isn't in the current working 
  68. directory.
  69.    The PATH environment variable lets us make a single copy of a program ac-
  70. cessible from any directory on the disk. This saves disk space.
  71.    At present, my path is set to:
  72.  
  73. E:;C:\bin;C:\;
  74.  
  75. which says: Search drive "E:" (a RAM disk) first, and if you don't find the 
  76. file there, try "C:\bin". If that fails, try "C:\". If all three path names 
  77. fail, MS-DOS gives up and issues an error message. Notice that each path name 
  78. in the PATH environment area is separated by a semicolon.
  79.    To set the PATH environment variable, all you do is type in:
  80.  
  81. C>PATH=E:;C:\bin;C:\;
  82.  
  83.    If you type:
  84.  
  85. C>set
  86.  
  87. and press ENTER, you'll see the status of your environment variables. The use 
  88. of the PATH environment variable solves one of our design problems: accessing
  89. the program from any place in the system. I use the "bin" directory off the 
  90. root directory to hold all of my executable files, so that's where I'll store 
  91. the directory program. (When I finish writing it.)
  92.  
  93. DATA ALTERNATIVES
  94.    Next, how do I want to access the information needed for each directory
  95. entry ?
  96.    My first thought was to code the directory paths as a series of pointers to
  97. chars, something like:
  98.  
  99. char *paths[] = {
  100.    "Karol D: \family\words\karol",
  101.    "Katie D: \family\words\katie",
  102.    "project C: \eco88\source\project1",
  103.    0
  104. };
  105.  
  106.    This data structure would work okay, but I'd have to recompile the prog-
  107. ram each time I want to add to, or otherwise change, the abbreviations for a 
  108. directory path. (The last entry is zero so I would be able to sense the end of 
  109. the list easily.)
  110.    By now, the final solution should be obvious. Because we need a flexible 
  111. means of storing directory path names, we'll use a text file.
  112.    Now that we know: 1) the data requirements for the program, 2) how to
  113. access that data from any point on the disk, and 3) how the data will be 
  114. stored, writing the program is fairly easy.
  115.  
  116. THE SOLUTION
  117.    The program supplied in the archive file is the solution to the problem. I
  118. wrote it with the Eco-C88 Rel. 4.0 C compiler, but it should be compatible 
  119. with almost any MS-DOS C compiler. (( TYPIST'S NOTE: I compiled the program 
  120. with Microsoft's Quick C Ver. 1.0 compiler and it compiled fine.))  I've used 
  121. prototyping in the program, but you can easily change the prototypes to the 
  122. standard K&R format.
  123.    The program begins with header files and definitions. Note that "get_dat"
  124. is the data file.
  125.  
  126. FINDING THE DATA
  127.    Once in main(), the program makes sure there are two arguments on the com-
  128. mand line. Therefore, if I want to go to my test project, I would enter:
  129.  
  130. C>get project1
  131.  
  132.    If I'd just entered "get" the program would quit with an error message.
  133. Note: the program assumes that MS-DOS's PATH environment variable points to 
  134. the program(get.exe) and the data file(get.dat).
  135.    The call to open_data_file() does more than simply open the data file. As
  136. I mentioned above, the PATH variable can have multiple paths. Therefore, it is 
  137. necessary to read, or parse, the PATH environment data to find which path 
  138. holds the data file we need.
  139.    Inside open_data_file(), the call to getenv() returns a pointer to the 
  140. PATH environment variable. If PATH is not set, a NULL pointer returns and the 
  141. program ends. Assiming that PATH has been set, the pointer will be non-NULL. 
  142. On my ststem, ptr would point to:
  143.  
  144. E:;C:\bin;C:\;
  145.  
  146.    The problem now is to separate the paths to find which one holds our data
  147. file. To do this, we copy the PATH information from ptr into the p[] character 
  148. array by a call to strcpy().
  149.    Next, we use strtok() to break the PATH string into its sub-parts (watch-
  150. ing for the semicolon delimiter). We won't use strtok() that often, but it's 
  151. wonderful when we need it. It's also part of the (proposed) ANSI and UNIX 
  152. System V standard libraries.
  153.    In short, strtok() searches a string (the first argument of the function) 
  154. using a list of one or more characters from the second string. Our first call 
  155. to strtok() searches p[] using the semicolon as a delimiter. If strtok() finds 
  156. a semicolon, it forms a string of what was read up to that point and returns a 
  157. pointer to it.
  158.    If a non-null pointer is returned from strtok() it will have returned a
  159. pointer to a string. In our case, it would be:
  160.  
  161. ptr = "E:"
  162.  
  163.    This is copied into temp[] by a call to strcpy() and a backslash is them
  164. appended to it. The second call to strcat() adds the data file name to the 
  165. string with the result:
  166.  
  167. temp[] = E:\get.dat
  168.  
  169.    We then try to open a file using the full pathneme just built. If we're in
  170. the wrong directory for the get.dat data file, a NULL pointer is returned. 
  171. Since we may still have more PATH directories to examine, we clear out temp[] 
  172. and call strtok() again.
  173.    Because the first argument to strtok() is cast to a NULL character pointer,
  174. strtok() continues to parse the previous string. If you follow through the 
  175. second pass, temp[] will hold:
  176.  
  177. temp[] = C:\bin\get.dat
  178.  
  179. and the third pass would be:
  180.  
  181. temp[] = C:\get.dat
  182.  
  183.    Assuming that one of the PATH strings does hold the get.dat data file, 
  184. FILE pointer fpin will be non-NULL and we break out of the while loop. (If we 
  185. exhaust the PATH possibilities, strtok() will return a NULL pointer and the 
  186. while loop ends. The next if test would find a NULL in fpin and the program 
  187. would end.)
  188.    Assuming open_data_file() returns a valid FILE pointer, the call to 
  189. search_file() passes the FILE pointer and the command line abbreviation for 
  190. the directory path wanted by the user (e.g., "project1"). The search_file() 
  191. function reads the get.dat data file one line at a time, using the newline 
  192. character ('\n') to sense the end of each directory name. The program assumes 
  193. the data is stored in the form:
  194.  
  195. abbreviation  drive-name
  196. directory-pathname
  197.  
  198. or
  199.  
  200. "project C: \eco88\tools\source\project1"
  201.  
  202. with one blank space between each of the three data items. Note that we use
  203. strtok() again to parse the string read from the data file, using a blank 
  204. space as the delimiter this time. After the first call, ptr would point to 
  205. "project1".
  206.    In the if statement, strcmp() checks ptr against "where" for a match. Since
  207. "where" is the command line abbreviation for the directory path wanted by the 
  208. user, we're checking to see if the abbreviation exists in the get.dat data 
  209. file. If we find a match, further calls to strtok() break the string up into 
  210. the drive (drive[]) and path (path[]) information and return a MATCH flag. If 
  211. no match is found, the FAIL flag gets set.
  212.    If MATCH is found, we call do_switch(). The system() function performs a 
  213. command.com-type directive to MS-DOS. Therefore, if drive[] contains "D:", 
  214. it's as if that were typed in at the keyboard, thus moving control to drive D.
  215.    The chdir() function changes the current working directory to the one spec-
  216. ified by the argument passed to chdir(). Since path[] has the full path name 
  217. for our desired directory, chdir() puts us in that directory and returns 
  218. control to main(). If chdir() doesn't find the directory, it displays an error 
  219. message. A successful chdir() ends the program and you're in the desired 
  220. directory.
  221.  
  222. PARSING THOUGHTS
  223.    Although the problem itself is useful, the idea of replacing program data
  224. with a data file is particularly interesting. Not too long ago, I wanted to 
  225. write a CAI (computer aided instruction) on the C language.
  226.    I started out writing printf()'s but Tim Leslie, a colleague and friend,
  227. convinced me that a better approach would be to write a Pilot-like interpreter 
  228. instead. He was right.
  229.    While the initial costs were higher (it took almost a month to write the
  230. interpreter), the result is a program that lets me write and test new CAI's in 
  231. weeks rather than months.
  232.    The interpreter is very similar to what I've presented here; parsing prog-
  233. ram lines, finding out what was read in the parse, and then acting on it. (If 
  234. you think about it, interpreters are little more than parsers with a symbol 
  235. table.)
  236.    Usint ASCII text files for storing data shouldn't be limited to large
  237. database-type projects either. Tim used this approach to write a simple 
  238. metric-to-decimal conversion program for his father.
  239.    Then when his father wanted to add new conversions, he used his word pro-
  240. cessor to add them. Try that when the data is buried inside the program code.
  241. **************************  END OF TEXT *************************************
  242.  
  243.