Parent Directory
|
Revision Log
Revision 1 - (view) (download)
| 1 : | root | 1 | This is unix.info, produced by makeinfo version 4.0 from unix.texinfo. |
| 2 : | |||
| 3 : | |||
| 4 : | File: unix.info, Node: search and replace, Next: WWW example, Prev: Pattern matching, Up: Perl | ||
| 5 : | |||
| 6 : | Searching and replacing text | ||
| 7 : | ============================ | ||
| 8 : | |||
| 9 : | The `sed'-like function for replacing all occurances of a string is | ||
| 10 : | easily implemented in Perl using | ||
| 11 : | |||
| 12 : | while (<input>) | ||
| 13 : | { | ||
| 14 : | s/$search/$replace/g; | ||
| 15 : | print output; | ||
| 16 : | } | ||
| 17 : | |||
| 18 : | This example replaces the string inside the default variable. To replace | ||
| 19 : | in a general variable we use the operator `=~', with syntax: | ||
| 20 : | |||
| 21 : | $variable =~ s/SEARCH/REPLACE/ | ||
| 22 : | |||
| 23 : | Here is an example of some of this operator in use. The following is | ||
| 24 : | a program which searches and replaces a string in several files. This | ||
| 25 : | is useful program indeed for making a change globally in a group of | ||
| 26 : | files! The program is called `file-replace'. | ||
| 27 : | |||
| 28 : | #!/local/bin/perl | ||
| 29 : | ############################################################## | ||
| 30 : | # | ||
| 31 : | # Look through files for findstring and change to newstring | ||
| 32 : | # in all files. | ||
| 33 : | # | ||
| 34 : | ############################################################## | ||
| 35 : | |||
| 36 : | # | ||
| 37 : | # Define a temporary file and check it doesn't exist | ||
| 38 : | # | ||
| 39 : | |||
| 40 : | $outputfile = "tmpmarkfind"; | ||
| 41 : | unlink $outputfile; | ||
| 42 : | |||
| 43 : | # | ||
| 44 : | # Check command line for list of files | ||
| 45 : | # | ||
| 46 : | |||
| 47 : | if ($#ARGV < 0) | ||
| 48 : | { | ||
| 49 : | die "Syntax: file-replace [file list]\n"; | ||
| 50 : | } | ||
| 51 : | |||
| 52 : | print "Enter the string you want to find (Don't use quotes):\n\n:"; | ||
| 53 : | $findstring=<STDIN>; | ||
| 54 : | chop $findstring; | ||
| 55 : | |||
| 56 : | print "Enter the string you want to replace with (Don't use quotes):\n\n:"; | ||
| 57 : | $replacestring=<STDIN>; | ||
| 58 : | chop $replacestring; | ||
| 59 : | |||
| 60 : | # | ||
| 61 : | |||
| 62 : | print "\nFind: $findstring\n"; | ||
| 63 : | print "Replace: $replacestring\n"; | ||
| 64 : | print "\nConfirm (y/n) "; | ||
| 65 : | $y = <STDIN>; | ||
| 66 : | chop $y; | ||
| 67 : | |||
| 68 : | if ( $y ne "y") | ||
| 69 : | { | ||
| 70 : | die "Aborted -- nothing done.\n"; | ||
| 71 : | } | ||
| 72 : | else | ||
| 73 : | { | ||
| 74 : | print "Use CTRL-C to interrupt...\n"; | ||
| 75 : | } | ||
| 76 : | |||
| 77 : | # | ||
| 78 : | # Now shift default array @ARGV to get arguments 1 by 1 | ||
| 79 : | # | ||
| 80 : | |||
| 81 : | while ($file = shift) | ||
| 82 : | { | ||
| 83 : | if ($file eq "file-replace") | ||
| 84 : | { | ||
| 85 : | print "Findmark will not operate on itself!"; | ||
| 86 : | next; | ||
| 87 : | } | ||
| 88 : | |||
| 89 : | # | ||
| 90 : | # Save existing mode of file for later | ||
| 91 : | # | ||
| 92 : | |||
| 93 : | ($dev,$ino,$mode)=stat($file); | ||
| 94 : | |||
| 95 : | open (INPUT,$file) || warn "Couldn't open $file\n"; | ||
| 96 : | open (OUTPUT,"> $outputfile") || warn "Can't open tmp"; | ||
| 97 : | |||
| 98 : | $notify = 1; | ||
| 99 : | |||
| 100 : | while (<INPUT>) | ||
| 101 : | { | ||
| 102 : | if (/$findstring/ && $notify) | ||
| 103 : | { | ||
| 104 : | print "Fixing $file...\n"; | ||
| 105 : | $notify = 0; | ||
| 106 : | } | ||
| 107 : | s/$findstring/$replacestring/g; | ||
| 108 : | print OUTPUT; | ||
| 109 : | } | ||
| 110 : | |||
| 111 : | close (OUTPUT); | ||
| 112 : | |||
| 113 : | # | ||
| 114 : | # If nothing went wrong (if outfile not empty) | ||
| 115 : | # move temp file to original and reset the | ||
| 116 : | # file mode saved above | ||
| 117 : | # | ||
| 118 : | |||
| 119 : | if (! -z $outputfile) | ||
| 120 : | { | ||
| 121 : | rename ($outputfile,$file); | ||
| 122 : | chmod ($mode,$file); | ||
| 123 : | } | ||
| 124 : | else | ||
| 125 : | { | ||
| 126 : | print "Warning: file empty!\n."; | ||
| 127 : | } | ||
| 128 : | } | ||
| 129 : | |||
| 130 : | Similarly we can search for lines containing a string. Here is the grep | ||
| 131 : | program written in perl | ||
| 132 : | |||
| 133 : | #!/local/bin/perl | ||
| 134 : | # | ||
| 135 : | # grep as a perl program | ||
| 136 : | # | ||
| 137 : | |||
| 138 : | # Check arguments etc | ||
| 139 : | |||
| 140 : | while (<>) | ||
| 141 : | { | ||
| 142 : | print if (/$ARGV[1]/); | ||
| 143 : | } | ||
| 144 : | |||
| 145 : | The operator `/SEARCH-STRING/' returns true if the search string is a | ||
| 146 : | substring of the default variable `$_'. To search an arbitrary string, | ||
| 147 : | we write | ||
| 148 : | .... if (TESTSTRING =~ /SEARCH-STRING/); | ||
| 149 : | |||
| 150 : | Here TESTSTRING is searched for occurrances of SEARCH-STRING and the | ||
| 151 : | result is true if one is found. | ||
| 152 : | |||
| 153 : | In perl you can use regular expressions to search for text patterns. | ||
| 154 : | Note however that, like all regular expression dialects, perl has its | ||
| 155 : | own conventions. For example the dollar sign does not mean "match the | ||
| 156 : | end of line" in perl, instead one uses the `\n' symbol. Here is an | ||
| 157 : | example program which illustrates the use of regular expressions in | ||
| 158 : | perl: | ||
| 159 : | |||
| 160 : | #!/local/bin/perl | ||
| 161 : | # | ||
| 162 : | # Test regular expressions in perl | ||
| 163 : | # | ||
| 164 : | # NB - careful with \ $ * symbols etc. Use '' quotes since | ||
| 165 : | # the shell interprets these! | ||
| 166 : | # | ||
| 167 : | |||
| 168 : | open (FILE,"regex_test"); | ||
| 169 : | |||
| 170 : | $regex = $ARGV[$#ARGV]; | ||
| 171 : | |||
| 172 : | print "Looking for $ARGV[$#ARGV] in file...\n"; | ||
| 173 : | |||
| 174 : | while (<FILE>) | ||
| 175 : | { | ||
| 176 : | if (/$regex/) | ||
| 177 : | { | ||
| 178 : | print; | ||
| 179 : | } | ||
| 180 : | } | ||
| 181 : | |||
| 182 : | |||
| 183 : | # | ||
| 184 : | # Test like this: | ||
| 185 : | # | ||
| 186 : | # regex '.*' - prints every line (matches everything) | ||
| 187 : | # regex '.' - all lines except those containing only blanks | ||
| 188 : | # (. doesn't match ws/white-space) | ||
| 189 : | # regex '[a-z]' - matches any line containing lowercase | ||
| 190 : | # regex '[^a-z]' - matches any line containg something which is | ||
| 191 : | # not lowercase a-z | ||
| 192 : | # regex '[A-Za-z]' - matches any line containing letters of any kind | ||
| 193 : | # regex '[0-9]' - match any line containing numbers | ||
| 194 : | # regex '#.*' - line containing a hash symbol followed by anything | ||
| 195 : | # regex '^#.*' - line starting with hash symbol (first char) | ||
| 196 : | # regex ';\n' - match line ending in a semi-colon | ||
| 197 : | # | ||
| 198 : | |||
| 199 : | Try running this program with the test data on the following file which | ||
| 200 : | is called `regex_test' in the example program. | ||
| 201 : | |||
| 202 : | |||
| 203 : | |||
| 204 : | # A line beginning with a hash symbol | ||
| 205 : | |||
| 206 : | JUST UPPERCASE LETTERS | ||
| 207 : | |||
| 208 : | just lowercase letters | ||
| 209 : | |||
| 210 : | Letters and numbers 123456 | ||
| 211 : | |||
| 212 : | 123456 | ||
| 213 : | |||
| 214 : | A line ending with a semi-colon; | ||
| 215 : | |||
| 216 : | Line with a comment # COMMENT... | ||
| 217 : | |||
| 218 : | |||
| 219 : | File: unix.info, Node: WWW example, Next: WWW example 2, Prev: search and replace, Up: Perl | ||
| 220 : | |||
| 221 : | Example: convert mail to WWW pages | ||
| 222 : | ================================== | ||
| 223 : | |||
| 224 : | Here is an example program which you could use to automatically turn | ||
| 225 : | a mail message of the form | ||
| 226 : | |||
| 227 : | From: Newswire | ||
| 228 : | To: Mail2html | ||
| 229 : | Subject: Nothing happened | ||
| 230 : | |||
| 231 : | On the 13th February at kl. 09:30 nothing happened. No footprints | ||
| 232 : | were found leading to the scene of a terrible murder, no evidence | ||
| 233 : | of a struggle .... etc etc | ||
| 234 : | |||
| 235 : | into an html-file for the world wide web. The program works by | ||
| 236 : | extracting the message body and subject from the mail and writing | ||
| 237 : | html-commands around these to make a web page. The subject field of | ||
| 238 : | the mail becomes the title. The other headers get skipped, since the | ||
| 239 : | script searches for lines containing the sequence "colon-space" or `: | ||
| 240 : | '. A regular expression is used for this. | ||
| 241 : | |||
| 242 : | #!/local/bin/perl | ||
| 243 : | # | ||
| 244 : | # Make HTML from mail | ||
| 245 : | # | ||
| 246 : | |||
| 247 : | &BeginWebPage(); | ||
| 248 : | &ReadNewMail(); | ||
| 249 : | &EndWebPage(); | ||
| 250 : | |||
| 251 : | |||
| 252 : | ########################################################## | ||
| 253 : | |||
| 254 : | sub BeginWebPage | ||
| 255 : | |||
| 256 : | { | ||
| 257 : | print "<HTML>\n"; | ||
| 258 : | print "<BODY>\n"; | ||
| 259 : | } | ||
| 260 : | |||
| 261 : | ########################################################## | ||
| 262 : | |||
| 263 : | sub EndWebPage | ||
| 264 : | |||
| 265 : | { | ||
| 266 : | print "</BODY>\n"; | ||
| 267 : | print "</HTML>\n"; | ||
| 268 : | } | ||
| 269 : | |||
| 270 : | ########################################################## | ||
| 271 : | |||
| 272 : | sub ReadNewMail | ||
| 273 : | |||
| 274 : | { | ||
| 275 : | while (<>) | ||
| 276 : | { | ||
| 277 : | if (/Subject:/) # Search for subject line | ||
| 278 : | { | ||
| 279 : | # Extract subject text... | ||
| 280 : | |||
| 281 : | chop; | ||
| 282 : | ($left,$right) = split(":",$_); | ||
| 283 : | print "<H1> $right </H1>\n"; | ||
| 284 : | next; | ||
| 285 : | } | ||
| 286 : | elsif (/.*: .*/) # Search for - anything: anything | ||
| 287 : | { | ||
| 288 : | next; # skip other headers | ||
| 289 : | } | ||
| 290 : | |||
| 291 : | print; | ||
| 292 : | } | ||
| 293 : | } | ||
| 294 : | |||
| 295 : | |||
| 296 : | File: unix.info, Node: WWW example 2, Next: Other functions, Prev: WWW example, Up: Perl | ||
| 297 : | |||
| 298 : | Generate WWW pages automagically | ||
| 299 : | ================================ | ||
| 300 : | |||
| 301 : | The following program scans through the password database and build | ||
| 302 : | a standardized html-page for each user it finds there. It fills in the | ||
| 303 : | name of the user in each case. Note the use of the `<<' operator for | ||
| 304 : | extended input, already used in the context of the shell, *Note Pipes | ||
| 305 : | and redirection::. This allows us to format a whole passage of text, | ||
| 306 : | inserting variables at strategic places, and avoid having to the | ||
| 307 : | `print' over many lines. | ||
| 308 : | |||
| 309 : | |||
| 310 : | #!/local/bin/perl | ||
| 311 : | # | ||
| 312 : | # Build a default home page for each user in /etc/passwd | ||
| 313 : | # | ||
| 314 : | # | ||
| 315 : | |||
| 316 : | #################################################################### | ||
| 317 : | # Level 0 (main) | ||
| 318 : | #################################################################### | ||
| 319 : | |||
| 320 : | $true = 1; | ||
| 321 : | $false = 0; | ||
| 322 : | |||
| 323 : | # First build an associated array of users and full names | ||
| 324 : | |||
| 325 : | setpwent(); | ||
| 326 : | |||
| 327 : | while ($true) | ||
| 328 : | { | ||
| 329 : | ($name,$passwd,$uid,$gid,$quota,$comment,$fullname) = getpwent; | ||
| 330 : | $FullName{$name} = $fullname; | ||
| 331 : | print "$name - $FullName{$name}\n"; | ||
| 332 : | last if ($name eq ""); | ||
| 333 : | } | ||
| 334 : | |||
| 335 : | print "\n"; | ||
| 336 : | |||
| 337 : | # Now make a unique filename for each page and open a file | ||
| 338 : | |||
| 339 : | foreach $user (sort keys(%FullName)) | ||
| 340 : | { | ||
| 341 : | next if ($user eq ""); | ||
| 342 : | |||
| 343 : | print "Making page for $user\n"; | ||
| 344 : | $outputfile = "$user.html"; | ||
| 345 : | |||
| 346 : | open (OUT,"> $outputfile") || die "Can't open $outputfile\n"; | ||
| 347 : | |||
| 348 : | &MakePage; | ||
| 349 : | |||
| 350 : | close (OUT); | ||
| 351 : | } | ||
| 352 : | |||
| 353 : | |||
| 354 : | #################################################################### | ||
| 355 : | # Level 1 | ||
| 356 : | #################################################################### | ||
| 357 : | |||
| 358 : | sub MakePage | ||
| 359 : | |||
| 360 : | { | ||
| 361 : | print OUT <<ENDMARKER; | ||
| 362 : | |||
| 363 : | <HTML> | ||
| 364 : | <BODY> | ||
| 365 : | <HEAD><TITLE>$FullName{$user}'s Home Page</TITLE></HEAD> | ||
| 366 : | <H1>$FullName{$user}'s Home Page</H1> | ||
| 367 : | |||
| 368 : | Hi welcome to my home page. In case you hadn't | ||
| 369 : | got it yet my name is: $FullName{$user}... | ||
| 370 : | |||
| 371 : | I study at <a href=http://www.iu.hioslo.no>Høgskolen i Oslo</a>. | ||
| 372 : | |||
| 373 : | </BODY> | ||
| 374 : | </HTML> | ||
| 375 : | |||
| 376 : | ENDMARKER | ||
| 377 : | } | ||
| 378 : | |||
| 379 : | |||
| 380 : | File: unix.info, Node: Other functions, Next: Perl summary, Prev: WWW example 2, Up: Perl | ||
| 381 : | |||
| 382 : | Other supported functions | ||
| 383 : | ========================= | ||
| 384 : | |||
| 385 : | Perl has very many functions which come directly from the C library. | ||
| 386 : | To give a taster, a few are listed here. The Perl book contains a | ||
| 387 : | comprehensive description of these. | ||
| 388 : | |||
| 389 : | _Fork_ | ||
| 390 : | The standard UNIX fork command for spawning new processes. | ||
| 391 : | |||
| 392 : | _Sockets_ | ||
| 393 : | Support for network socket communication. | ||
| 394 : | |||
| 395 : | _Directories_ | ||
| 396 : | Directory opening and handling routines. | ||
| 397 : | |||
| 398 : | _Databases_ | ||
| 399 : | Reading from the password files and the host databases is | ||
| 400 : | supported through the standard C functions `getpasswdbyname' etc. | ||
| 401 : | dressed up to look like Perl. | ||
| 402 : | |||
| 403 : | _Crypt_ | ||
| 404 : | The password encryption function. | ||
| 405 : | |||
| 406 : | _Regexp_ | ||
| 407 : | Regular expressions and pattern matching, search and replace | ||
| 408 : | functions as in `sed'. | ||
| 409 : | |||
| 410 : | _Operators_ | ||
| 411 : | Perl has the full set of C's logical operators. | ||
| 412 : | |||
| 413 : | _File testing_ | ||
| 414 : | Tests from the shell like `if (-f file)'. | ||
| 415 : | |||
| 416 : | Here are some of the most frequently used functions | ||
| 417 : | |||
| 418 : | `chmod' | ||
| 419 : | Change the file mode of a file. e.g. `chmod 755,FILENAME' | ||
| 420 : | |||
| 421 : | `chdir' | ||
| 422 : | Change the current working directory. e.g. `chdir /etc' | ||
| 423 : | |||
| 424 : | `stat' | ||
| 425 : | Get info about permissions, ownership and type of a file. | ||
| 426 : | |||
| 427 : | `open' | ||
| 428 : | Open a file for reading, `>' writing, `|' as a pipe. | ||
| 429 : | |||
| 430 : | `close' | ||
| 431 : | Close an open file handle. | ||
| 432 : | |||
| 433 : | `system' | ||
| 434 : | Execute a shell command as a child process. e.g. `system "ls";' | ||
| 435 : | |||
| 436 : | `split' | ||
| 437 : | Split a string variable into an array of elements, by searching | ||
| 438 : | for a special character (space or `:' etc.) e.g. | ||
| 439 : | `@array=split(":",$string)'. | ||
| 440 : | |||
| 441 : | `rename' | ||
| 442 : | Rename a file. e.g. `rename OLD NAME NEW-NAME' | ||
| 443 : | |||
| 444 : | `mkdir' | ||
| 445 : | Make a new directory. `mkdir NEWDIR' | ||
| 446 : | |||
| 447 : | `shift' | ||
| 448 : | Read the first element of an array and delete it, shifting all the | ||
| 449 : | array elements down by one. (e.g. `$first=shift(@array);)'. | ||
| 450 : | |||
| 451 : | `chop' | ||
| 452 : | Chops off the last character of a string. Often used for deleting | ||
| 453 : | the end-of-line character when reading from a file. | ||
| 454 : | |||
| 455 : | `oct' | ||
| 456 : | Interprets a number as octal (converts to decimal). e.g. | ||
| 457 : | `$decimal = oct(755);' | ||
| 458 : | |||
| 459 : | `kill' | ||
| 460 : | Send a kill signal to a list of processes. e.g. `kill -9, | ||
| 461 : | PID1,PID2...' | ||
| 462 : | |||
| 463 : | You should explore Perl's possibilities yourself. Perl is a good | ||
| 464 : | alternative to the shell which has much of the power of C and is | ||
| 465 : | therefore ideal for simple and more complex system programming tasks. | ||
| 466 : | If you intend to be a system administrator for UNIX systems, you could | ||
| 467 : | do much worse than to read the Perl book and learn Perl inside out. | ||
| 468 : | |||
| 469 : | |||
| 470 : | File: unix.info, Node: Perl summary, Next: Ex5, Prev: Other functions, Up: Perl | ||
| 471 : | |||
| 472 : | Summary | ||
| 473 : | ======= | ||
| 474 : | |||
| 475 : | The Practical Extraction and Report Language is a powerful tool which | ||
| 476 : | goes beyond shell programming, but which retains much of the | ||
| 477 : | immediateness of shell programming in a more formal programming | ||
| 478 : | environment. | ||
| 479 : | |||
| 480 : | The success of Perl has led many programmers to use it exclusively. | ||
| 481 : | In the next section, I would like to argue that programming directly in | ||
| 482 : | C is not much harder. In fact it has advantages in the long run. The | ||
| 483 : | power of Perl is that it is as _immediate_ as shell programming. If you | ||
| 484 : | are inexperienced, Perl is a little easier than C because many features | ||
| 485 : | are ready programmed into the language, but with time one also builds up | ||
| 486 : | a repertoire of C functions which can do the same tricks. | ||
| 487 : | |||
| 488 : | |||
| 489 : | File: unix.info, Node: Ex5, Next: Proj5, Prev: Perl summary, Up: Perl | ||
| 490 : | |||
| 491 : | Exercises | ||
| 492 : | ========= | ||
| 493 : | |||
| 494 : | 1. Write a progam which prints out all of its arguments alphabetically | ||
| 495 : | together with the first and the last, and the number of arguments. | ||
| 496 : | |||
| 497 : | 2. Write a program which prints out the pathname of the home directory | ||
| 498 : | for a given user. The user's login name should be given as an | ||
| 499 : | argument. | ||
| 500 : | |||
| 501 : | 3. Write a program called `search-replace' which looks for a given | ||
| 502 : | string in a list of files and replaces it with a new string. You | ||
| 503 : | should be able to specify a list of files using ordinary unix | ||
| 504 : | wildcards. e.g. `search-replace search-string replace-string | ||
| 505 : | *.text'. This is a dangerous operation! What if the user types the | ||
| 506 : | strings incorrectly? How can you may the program safer? | ||
| 507 : | |||
| 508 : | 4. Write a program which opens a pipe from `ps' and computes the | ||
| 509 : | total cpu-time used by each user. Print the results in order of | ||
| 510 : | maximum to minimum. Hint: use an associated array to store the | ||
| 511 : | information. | ||
| 512 : | |||
| 513 : | 5. Write a program which forks and goes into the background. Make the | ||
| 514 : | program send you mail when some other user of your choice logs in. | ||
| 515 : | Use sleep to check only every few minutes. | ||
| 516 : | |||
| 517 : | 6. Open a pipe from `find' and collect statistics over how many files | ||
| 518 : | there are in all of your sub-directories. | ||
| 519 : | |||
| 520 : | |||
| 521 : | File: unix.info, Node: Proj5, Prev: Ex5, Up: Perl | ||
| 522 : | |||
| 523 : | Project | ||
| 524 : | ======= | ||
| 525 : | |||
| 526 : | Write a program which checks the `sanity' of your UNIX system. | ||
| 527 : | 1. Check that the password file /etc/passwd is not writable by | ||
| 528 : | general users. | ||
| 529 : | |||
| 530 : | 2. Check that the processes `cron' and `sendmail' are running. | ||
| 531 : | |||
| 532 : | 3. Check that, if the file `/etc/exports' or `/etc/dfs/dfstab' | ||
| 533 : | exists, the _nfsd_ daemon is running. | ||
| 534 : | |||
| 535 : | 4. Check that if the filesystem table `/etc/fstab' (or its equivalent | ||
| 536 : | on non-BSD systems) contains NFS mounted filesystems, the `biod' | ||
| 537 : | or `nfsiod' daemon is running. | ||
| 538 : | |||
| 539 : | 5. Check that the file `/etc/resolv.conf' contains the correct domain | ||
| 540 : | name. It may or may not be the same as that returned by the shell | ||
| 541 : | command `domainname'. If it is not the same, you should print the | ||
| 542 : | message `NIS domain has different name to DNS domain'. | ||
| 543 : | |||
| 544 : | |||
| 545 : | |||
| 546 : | File: unix.info, Node: WWW and CGI programming, Next: C programming, Prev: Perl, Up: Top | ||
| 547 : | |||
| 548 : | WWW and CGI programming | ||
| 549 : | *********************** | ||
| 550 : | |||
| 551 : | CGI stands for the Common Gateway Interface. It is the name given to | ||
| 552 : | scripts which can be executed from within pages of the world wide web. | ||
| 553 : | Although it is possible to use any language in CGI programs (hence the | ||
| 554 : | word `common'), the usual choice is Perl, because of the ease with | ||
| 555 : | which Perl can handle text. | ||
| 556 : | |||
| 557 : | The CGI interface is pretty unintelligent, in order to be as general | ||
| 558 : | as possible, so we need to do a bit of work in order to make scripts | ||
| 559 : | work. | ||
| 560 : | |||
| 561 : | * Menu: | ||
| 562 : | |||
| 563 : | * Permissions:: | ||
| 564 : | * Protocols:: | ||
| 565 : | * HTML coding:: | ||
| 566 : | * Perl and the web:: | ||
| 567 : | * PHP and the web:: | ||
| 568 : | |||
| 569 : | |||
| 570 : | File: unix.info, Node: Permissions, Next: Protocols, Prev: WWW and CGI programming, Up: WWW and CGI programming | ||
| 571 : | |||
| 572 : | Permissions | ||
| 573 : | =========== | ||
| 574 : | |||
| 575 : | The key thing about the WWW which often causes a lot of confusion is | ||
| 576 : | that the W3 service runs with a user ID of `nobody'. The purpose of | ||
| 577 : | this is to ensure that nobody has the right to read or write files | ||
| 578 : | unless they are opened very explicitly by the user who owns them. | ||
| 579 : | |||
| 580 : | In order for files to be readable on the WWW, they must have file | ||
| 581 : | mode `644' and they must lie in a directory which has mode `755'. In | ||
| 582 : | order for a CGI program to be executable, it must have permission `755' | ||
| 583 : | and in order for such a program to write to a file in a user's | ||
| 584 : | directory, it must be possible for the file to be created (if | ||
| 585 : | necessary) and everyone must be able to write to it. That means that | ||
| 586 : | files which are written to by the WWW must have mode `666' and must | ||
| 587 : | either exist already or lie in a directory with permission `777'(1). | ||
| 588 : | |||
| 589 : | ---------- Footnotes ---------- | ||
| 590 : | |||
| 591 : | (1) You could also set the sticky bit `1777' in order to prevent | ||
| 592 : | malicious users from deleting your file. | ||
| 593 : | |||
| 594 : | |||
| 595 : | File: unix.info, Node: Protocols, Next: HTML coding, Prev: Permissions, Up: WWW and CGI programming | ||
| 596 : | |||
| 597 : | Protocols | ||
| 598 : | ========= | ||
| 599 : | |||
| 600 : | CGI script programs communicate with W3 browsers using a very simple | ||
| 601 : | protocol. It goes like this: | ||
| 602 : | |||
| 603 : | * A web page sends data to a script using the `forms' interface. | ||
| 604 : | Those data are concatenated into _a single line_. The data in | ||
| 605 : | separate fields of a form are separated by `&' signs. New lines | ||
| 606 : | are replaced by the text `%0D%0A', which is the DOS ASCII | ||
| 607 : | representation of a newline, and spaces are replaced by `+' | ||
| 608 : | symbols. | ||
| 609 : | |||
| 610 : | * A CGI script reads this single line of text on the standard input. | ||
| 611 : | |||
| 612 : | * The CGI script replies to the web browser. The first line of the | ||
| 613 : | reply _must_ be a line which is tells the browser what mime-type | ||
| 614 : | the data are sent in. Usually, a CGI script replies in HTML code, | ||
| 615 : | in which case the first line in the reply must be: | ||
| 616 : | |||
| 617 : | Content-type: text/html | ||
| 618 : | |||
| 619 : | This must be followed by a blank line. | ||
| 620 : | |||
| 621 : | |||
| 622 : | |||
| 623 : | File: unix.info, Node: HTML coding, Next: Perl and the web, Prev: Protocols, Up: WWW and CGI programming | ||
| 624 : | |||
| 625 : | HTML coding of forms | ||
| 626 : | ==================== | ||
| 627 : | |||
| 628 : | To start a CGI program from a web page we use a _form_ which is a | ||
| 629 : | part of the HTML code enclosed with the parentheses | ||
| 630 : | |||
| 631 : | |||
| 632 : | <FORM method="POST" ACTION="/cgi-script-alias/program.pl"> | ||
| 633 : | ... | ||
| 634 : | </FORM> | ||
| 635 : | |||
| 636 : | The method `post' means that the data which get typed into this form | ||
| 637 : | will be piped into the CGI program via its standard input. The `action' | ||
| 638 : | specifies which program you want to start. Note that you cannot simply | ||
| 639 : | use the absolute path of the file, for security reasons. You must use | ||
| 640 : | something called a `script alias' to tell the web browser where to find | ||
| 641 : | the program. If you do not have a script alias defined for you | ||
| 642 : | personally, then you need to get one from your system administrator. | ||
| 643 : | By using a script alias, no one from outside your site can see where | ||
| 644 : | your files are located, only that you have a `cgi-bin' area somewhere | ||
| 645 : | on your system. | ||
| 646 : | |||
| 647 : | Within these parentheses, you can arrange to collect different kinds | ||
| 648 : | of input. The simplest kind of input is just a button which starts the | ||
| 649 : | CGI program. This has the form | ||
| 650 : | |||
| 651 : | <INPUT TYPE="submit" VALUE="Start my program"> | ||
| 652 : | |||
| 653 : | This code creates a button. When you click on it the program in your | ||
| 654 : | `action' string gets started. More generally, you will want to create | ||
| 655 : | input boxes where you can type in data. To create a single line input | ||
| 656 : | field, you use the following syntax: | ||
| 657 : | |||
| 658 : | <INPUT NAME="variable-name" SIZE=40> | ||
| 659 : | |||
| 660 : | This creates a single line text field of width 40 characters. This is | ||
| 661 : | not the limit on the length of the string which can be typed into the | ||
| 662 : | field, only a limit on the amount which is visible at any time. It is | ||
| 663 : | for visual formatting only. The NAME field is used to identify the data | ||
| 664 : | in the CGI script. The string you enter here will be sent to the CGI | ||
| 665 : | script in the form `variable-name=value of input...'. Another type of | ||
| 666 : | input is a text area. This is a larger box where one can type in text | ||
| 667 : | on several lines. The syntax is: | ||
| 668 : | |||
| 669 : | <TEXTAREA NAME="variable-name" ROW=50 COLS=50> | ||
| 670 : | |||
| 671 : | which means: create a text area of fifty rows by fifty columns with a | ||
| 672 : | prompt to the left of the box. Again, the size has only to do with the | ||
| 673 : | visual formatting, not to do with limits on the amount of text which | ||
| 674 : | can be entered. | ||
| 675 : | |||
| 676 : | As an example, let's create a WWW page with a complete form which | ||
| 677 : | can be used to make a guest book, or order form. | ||
| 678 : | |||
| 679 : | <HTML> | ||
| 680 : | <HEAD> | ||
| 681 : | <TITLE>Example form</TITLE> | ||
| 682 : | <!-- Comment: Mark Burgess, 27-Jan-1997 --> | ||
| 683 : | <LINK REV="made" HREF="mailto:mark@iu.hioslo.no"> | ||
| 684 : | </HEAD> | ||
| 685 : | <BODY> | ||
| 686 : | <CENTER><H1>Write in my guest book...</H1></CENTER> | ||
| 687 : | <HR> | ||
| 688 : | |||
| 689 : | <CENTER><H2>Please leave a comment using the form below.</H2><P> | ||
| 690 : | <FORM method="POST" ACTION="/cgi-bin-mark/comment.pl"> | ||
| 691 : | |||
| 692 : | Your Name/e-mail: <INPUT NAME="variable1" SIZE=40> <BR><BR> | ||
| 693 : | |||
| 694 : | <P> | ||
| 695 : | <TEXTAREA NAME="variable2" cols=50 rows=8></TEXTAREA> | ||
| 696 : | <P> | ||
| 697 : | |||
| 698 : | <INPUT TYPE=submit VALUE="Add message to book"> | ||
| 699 : | <INPUT TYPE=reset VALUE="Clear message"> | ||
| 700 : | </FORM> | ||
| 701 : | |||
| 702 : | <P> | ||
| 703 : | |||
| 704 : | </BODY> | ||
| 705 : | </HTML> | ||
| 706 : | |||
| 707 : | The reset button clears the form. When the submit button is pressed, | ||
| 708 : | the CGI program is activated. | ||
| 709 : | |||
| 710 : | |||
| 711 : | File: unix.info, Node: Perl and the web, Next: PHP and the web, Prev: HTML coding, Up: WWW and CGI programming | ||
| 712 : | |||
| 713 : | Perl and the web | ||
| 714 : | ================ | ||
| 715 : | |||
| 716 : | * Menu: | ||
| 717 : | |||
| 718 : | * Interpreting the data:: | ||
| 719 : | * A complete guestbook example:: | ||
| 720 : | |||
| 721 : | |||
| 722 : | File: unix.info, Node: Interpreting the data, Next: A complete guestbook example, Prev: Perl and the web, Up: Perl and the web | ||
| 723 : | |||
| 724 : | Interpreting data from forms | ||
| 725 : | ---------------------------- | ||
| 726 : | |||
| 727 : | To interpret and respond to the data in a form, we must write a | ||
| 728 : | program which satsifies the protocol above, *Note Protocols::. We use | ||
| 729 : | perl as a script langauge. The simplest valid CGI script is the | ||
| 730 : | following: | ||
| 731 : | |||
| 732 : | |||
| 733 : | #!/local/bin/perl | ||
| 734 : | |||
| 735 : | # | ||
| 736 : | # Reply with proper protocol | ||
| 737 : | # | ||
| 738 : | |||
| 739 : | print "Content-type: text/html\n\n"; | ||
| 740 : | |||
| 741 : | # | ||
| 742 : | # Get the data from the form ... | ||
| 743 : | # | ||
| 744 : | |||
| 745 : | $input = <STDIN>; | ||
| 746 : | |||
| 747 : | # | ||
| 748 : | # ... and echo them back | ||
| 749 : | # | ||
| 750 : | |||
| 751 : | print $input, "\n Done! \n"; | ||
| 752 : | |||
| 753 : | Although rather banal, this script is a useful starting point for CGI | ||
| 754 : | programming, because it shows you just how the input arrives at the | ||
| 755 : | script from the HTML form. The data arrive all in a single, enormously | ||
| 756 : | long line, full of funny characters. The first job of any script is to | ||
| 757 : | decode this line. | ||
| 758 : | |||
| 759 : | Before looking at how to decode the data, we should make an important | ||
| 760 : | point about the protocol line. If a web browser does not get this | ||
| 761 : | `Content-type' line from the CGI script it returns with an error: | ||
| 762 : | |||
| 763 : | |||
| 764 : | 500 Server Error | ||
| 765 : | |||
| 766 : | The server encountered an internal error or misconfiguration and was | ||
| 767 : | unable to complete your request. | ||
| 768 : | |||
| 769 : | Please contact the server administrator, and inform them of the time | ||
| 770 : | the error occurred, and anything you might have done that may have | ||
| 771 : | caused the error. | ||
| 772 : | |||
| 773 : | Error: HTTPd: malformed header from script www/cgi-bin/comment.pl | ||
| 774 : | |||
| 775 : | Before finishing your CGI script, you will probably ecounter this error | ||
| 776 : | several times. A common reason for getting the error is a syntax error | ||
| 777 : | in your script. If your program contains an error, the first thing a | ||
| 778 : | browser gets in return is not the `Content-type' line, but an error | ||
| 779 : | message. The browser does not pass on this error message, it just | ||
| 780 : | prints the uninformative message above. | ||
| 781 : | |||
| 782 : | If you can get the above script to work, then you are ready to | ||
| 783 : | decode the data which are sent to the script. The first thing is to use | ||
| 784 : | perl to split the long line into an array of lines, by splitting on | ||
| 785 : | `&'. We can also convert all of the `+' symbols back into spaces. The | ||
| 786 : | script now looks like this: | ||
| 787 : | |||
| 788 : | #!/local/bin/perl | ||
| 789 : | |||
| 790 : | # | ||
| 791 : | # Reply with proper protocol | ||
| 792 : | # | ||
| 793 : | |||
| 794 : | print "Content-type: text/html\n\n"; | ||
| 795 : | |||
| 796 : | # | ||
| 797 : | # Get the data from the form ... | ||
| 798 : | # | ||
| 799 : | |||
| 800 : | $input = <STDIN>; | ||
| 801 : | |||
| 802 : | # | ||
| 803 : | # ... and echo them back | ||
| 804 : | # | ||
| 805 : | |||
| 806 : | print "$input\n\n\n"; | ||
| 807 : | |||
| 808 : | $input =~ s/\+/ /g; | ||
| 809 : | |||
| 810 : | # | ||
| 811 : | # Now split the lines and convert | ||
| 812 : | # | ||
| 813 : | |||
| 814 : | @array = split('&',$input); | ||
| 815 : | |||
| 816 : | foreach $var ( @array ) | ||
| 817 : | { | ||
| 818 : | print "$var\n"; | ||
| 819 : | } | ||
| 820 : | |||
| 821 : | print "Done! \n"; | ||
| 822 : | |||
| 823 : | We now have a series of elements in our array. The output from this | ||
| 824 : | script is something like this: | ||
| 825 : | |||
| 826 : | |||
| 827 : | variable1=Mark+Burgess&variable2=%0D%0AI+just+called+to+say+ (WRAP) | ||
| 828 : | ....%0D%0A...hey+pig%2C+nothing%27s+working+out+the+way+I+planned | ||
| 829 : | variable1=Mark Burgess variable2=%0D%0AI just called to say (WRAP) | ||
| 830 : | ....%0D%0A...hey pig%2Cnothing%27s working out the way I planned Done! | ||
| 831 : | |||
| 832 : | As you can see, all control characters are converted into the form | ||
| 833 : | `%XX'. We should now try to do something with these. Since we are | ||
| 834 : | usually not interested in keeping new lines, or any other control | ||
| 835 : | codes, we can simply null-out these with a line of the form | ||
| 836 : | |||
| 837 : | |||
| 838 : | $input =~ s/%..//g; | ||
| 839 : | |||
| 840 : | The regular expression `%..' matches anything beginning with a percent | ||
| 841 : | symbol followed by two characters. The resulting output is then free of | ||
| 842 : | these symbols. We can then separate the variable contents from their | ||
| 843 : | names by splitting the input. Here is the complete code: | ||
| 844 : | |||
| 845 : | #!/local/bin/perl | ||
| 846 : | |||
| 847 : | # | ||
| 848 : | # Reply with proper protocol | ||
| 849 : | # | ||
| 850 : | |||
| 851 : | print "Content-type: text/html\n\n"; | ||
| 852 : | |||
| 853 : | # | ||
| 854 : | # Get the data from the form ... | ||
| 855 : | # | ||
| 856 : | |||
| 857 : | $input = <STDIN>; | ||
| 858 : | |||
| 859 : | # | ||
| 860 : | # ... and echo them back | ||
| 861 : | # | ||
| 862 : | |||
| 863 : | print "$input\n\n\n"; | ||
| 864 : | |||
| 865 : | $input =~ s/%..//g; | ||
| 866 : | |||
| 867 : | $input =~ s/\+/ /g; | ||
| 868 : | |||
| 869 : | @array = split('&',$input); | ||
| 870 : | |||
| 871 : | foreach $var ( @array ) | ||
| 872 : | { | ||
| 873 : | print "$var<br>"; | ||
| 874 : | } | ||
| 875 : | |||
| 876 : | print "<hr>\n"; | ||
| 877 : | |||
| 878 : | ($name,$variable1) = split("variable1=",$array[0]); | ||
| 879 : | ($name,$variable2) = split("variable2=",$array[1]); | ||
| 880 : | |||
| 881 : | print "<br>var1 = $variable1<br>"; | ||
| 882 : | print "<br>var2 = $variable2<br>"; | ||
| 883 : | |||
| 884 : | print "<br>Done! \n"; | ||
| 885 : | |||
| 886 : | and the output | ||
| 887 : | |||
| 888 : | variable1=Mark+Burgess&variable2=%0D%0AI+just+called+to+say (WRAP) | ||
| 889 : | +....%0D%0A...hey+pig%2C+nothing%27s+working+out+the+way+I+planned | ||
| 890 : | variable1=Mark Burgess | ||
| 891 : | variable2=I just called to say .......hey pig nothings working (WRAP) | ||
| 892 : | out the way I planned | ||
| 893 : | |||
| 894 : | |||
| 895 : | var1 = Mark Burgess | ||
| 896 : | |||
| 897 : | var2 = I just called to say .......hey pig nothings working out (WRAP) | ||
| 898 : | the way I planned | ||
| 899 : | |||
| 900 : | Done! | ||
| 901 : | |||
| 902 : | |||
| 903 : | File: unix.info, Node: A complete guestbook example, Prev: Interpreting the data, Up: Perl and the web | ||
| 904 : | |||
| 905 : | A complete guestbook example in perl | ||
| 906 : | ------------------------------------ | ||
| 907 : | |||
| 908 : | Let us now use this technique to develop a guest book aplication. | ||
| 909 : | Based on the code above, analyze the following code. | ||
| 910 : | |||
| 911 : | #!/local/bin/perl | ||
| 912 : | #################################################################### | ||
| 913 : | # | ||
| 914 : | # Guest book | ||
| 915 : | # | ||
| 916 : | #################################################################### | ||
| 917 : | |||
| 918 : | $guestbook_page = "/iu/nexus/ud/mark/www/tmp/cfguest.html"; | ||
| 919 : | |||
| 920 : | $tmp_page = "/iu/nexus/ud/mark/www/tmp/guests.tmp"; | ||
| 921 : | |||
| 922 : | $remote_host = $ENV{"REMOTE_HOST"}; | ||
| 923 : | |||
| 924 : | print "Content-type: text/html\n\n"; | ||
| 925 : | print "<br><hr><br>\n"; | ||
| 926 : | print "Thank you for submitting your comment!<br><br>\n"; | ||
| 927 : | print "best wishes,<br><br>"; | ||
| 928 : | print "-Mark<br><br><br>"; | ||
| 929 : | print "Return to <a href=http://www.iu.hioslo.no/~mark/menu.html>menu</a>\n"; | ||
| 930 : | |||
| 931 : | $input = <STDIN>; | ||
| 932 : | |||
| 933 : | $input =~ s/%..//g; | ||
| 934 : | |||
| 935 : | $input =~ s/\+/ /g; | ||
| 936 : | |||
| 937 : | @array = split('&',$input); | ||
| 938 : | |||
| 939 : | ($skip,$name) = split("var1=",$array[0]); | ||
| 940 : | ($skip,$message) = split("var2=",$array[1]); | ||
| 941 : | |||
| 942 : | if (! open (PAGE, $guestbook_page)) | ||
| 943 : | { | ||
| 944 : | print "Content-type: text/html\n\n"; | ||
| 945 : | print "couldn't open guestbook page file!"; | ||
| 946 : | } | ||
| 947 : | |||
| 948 : | if (! open (TMP, "+>$tmp_page")) | ||
| 949 : | { | ||
| 950 : | print "Content-type: text/html\n\n"; | ||
| 951 : | print "couldn't open temporary output file!"; | ||
| 952 : | } | ||
| 953 : | |||
| 954 : | while ($line = <PAGE>) | ||
| 955 : | { | ||
| 956 : | if ($line =~ /<h3>Number of entries: (..)/) | ||
| 957 : | { | ||
| 958 : | $entry_no = $1; | ||
| 959 : | $entry_no++; | ||
| 960 : | $line = "<h3>Number of entries: $entry_no </h3>\n"; | ||
| 961 : | } | ||
| 962 : | |||
| 963 : | if ($line =~ /<!-- LAST ENTRY -->/) | ||
| 964 : | { | ||
| 965 : | $date = `date +"%A, %b %d %Y"`; | ||
| 966 : | print TMP "<b>Entry $date from host: $remote_host</b>\n<p>\n"; | ||
| 967 : | print TMP "From: $name\n<p>\n"; | ||
| 968 : | print TMP $message; | ||
| 969 : | print TMP "\n<hr>\n"; | ||
| 970 : | } | ||
| 971 : | |||
| 972 : | print TMP "$line"; | ||
| 973 : | } | ||
| 974 : | |||
| 975 : | close PAGE; | ||
| 976 : | close TMP; | ||
| 977 : | |||
| 978 : | if (! rename ($tmp_page, $guestbook_page)) | ||
| 979 : | { | ||
| 980 : | print "Oops! Rename operation failed!\n"; | ||
| 981 : | } | ||
| 982 : | |||
| 983 : | chmod (0600, $guestbook_page); | ||
| 984 : | |||
| 985 : | This script works by reading through the old guest book file, | ||
| 986 : | opening a new copy of the guest book file and appending a new messages | ||
| 987 : | at the end. The end of the message section (not counting the `</HTML>' | ||
| 988 : | tags) is marked by a comment line. | ||
| 989 : | |||
| 990 : | <!-- LAST ENTRY --> | ||
| 991 : | |||
| 992 : | Note that a provisional guest book file has to exist in the first place. | ||
| 993 : | The script writes to a new file and then swaps the new file for the old | ||
| 994 : | one. The guest book file looks something like this: | ||
| 995 : | <html><head> | ||
| 996 : | <title>Comments</title> | ||
| 997 : | </head> | ||
| 998 : | <body> | ||
| 999 : | <h1>My guest book</h1> | ||
| 1000 : | |||
| 1001 : | <b>Entry no. Wednesday, Feb 28 1996 | ||
| 1002 : | from host: dax</b> | ||
| 1003 : | <p> | ||
| 1004 : | From: Mark.Burgess@iu.hioslo.no | ||
| 1005 : | <p> | ||
| 1006 : | Just to start the ball rolling.... | ||
| 1007 : | |||
| 1008 : | <hr> | ||
| 1009 : | |||
| 1010 : | <b>Entry no. Tuesday, Mar 26 1996 | ||
| 1011 : | from host: enterprise.subspace.net</b> | ||
| 1012 : | <p> | ||
| 1013 : | From: spock@enterprise | ||
| 1014 : | <p> | ||
| 1015 : | Registering a form of energy never before encountered. | ||
| 1016 : | |||
| 1017 : | <!-- LAST ENTRY --> | ||
| 1018 : | |||
| 1019 : | </body> <address><a href="http://www.iu.hioslo.no/~mark">Mark | ||
| 1020 : | Burgess</a> - Mark.Burgess@iu.hioslo.no</addre ss> </html> | ||
| 1021 : | The directory in which this file lies needs to be writable to the | ||
| 1022 : | user nobody (the WWW user) and the files within need to be deletable by | ||
| 1023 : | nobody but no one else. Some users try to make guest book scripts | ||
| 1024 : | setuid-themselves in order to overcome the problem that httpd runs with | ||
| 1025 : | uid nobody, but this opens many security issues. In short it is asking | ||
| 1026 : | for trouble. Unfortunately an ordinary user cannot use `chown' in order | ||
| 1027 : | to give access only to the WWW user nobody, so this approach needs the | ||
| 1028 : | cooperation of the system administrator. Nevertheless this is the most | ||
| 1029 : | secure approach. Try to work through this example step for step. | ||
| 1030 : | |||
| 1031 : | |||
| 1032 : | File: unix.info, Node: PHP and the web, Prev: Perl and the web, Up: WWW and CGI programming | ||
| 1033 : | |||
| 1034 : | PHP and the web | ||
| 1035 : | =============== | ||
| 1036 : | |||
| 1037 : | The PHP 3 language makes the whole business of web programming rather | ||
| 1038 : | simpler than perl. It hides the business of translating variables from | ||
| 1039 : | forms into new variables in a CGI program and it even allows you to | ||
| 1040 : | embed active code into you HTML pages. PHP has special support for | ||
| 1041 : | querying data in an SQL database like MySQL or Oracle. PHP documentation | ||
| 1042 : | lives at `http://www.php.net'. | ||
| 1043 : | |||
| 1044 : | * Menu: | ||
| 1045 : | |||
| 1046 : | * Embedded PHP:: | ||
| 1047 : | * PHP and forms:: | ||
| 1048 : | |||
| 1049 : | |||
| 1050 : | File: unix.info, Node: Embedded PHP, Next: PHP and forms, Prev: PHP and the web, Up: PHP and the web | ||
| 1051 : | |||
| 1052 : | Embedded PHP | ||
| 1053 : | ------------ | ||
| 1054 : | |||
| 1055 : | PHP code can be embedded inside HTML pages provided your WWW server | ||
| 1056 : | is configurered with PHP support. PHP code lives inside a tag with the | ||
| 1057 : | general form | ||
| 1058 : | |||
| 1059 : | <?php CODE... ?> | ||
| 1060 : | |||
| 1061 : | For example, we could use this to import one file into another and | ||
| 1062 : | print out a table of numbers: | ||
| 1063 : | <html> | ||
| 1064 : | <body> | ||
| 1065 : | |||
| 1066 : | <?php | ||
| 1067 : | |||
| 1068 : | include "file.html" | ||
| 1069 : | |||
| 1070 : | for ($i = 0; $i < 10; $i++) | ||
| 1071 : | { | ||
| 1072 : | print "Counting $i<br>"; | ||
| 1073 : | } | ||
| 1074 : | |||
| 1075 : | ?> | ||
| 1076 : | |||
| 1077 : | </body> | ||
| 1078 : | </html> | ||
| 1079 : | This makes it easy to generate WWW pages with a fixed visual layout: | ||
| 1080 : | |||
| 1081 : | <?php | ||
| 1082 : | # | ||
| 1083 : | # Standard layout | ||
| 1084 : | # | ||
| 1085 : | |||
| 1086 : | # Set $title, $comment and $contents | ||
| 1087 : | |||
| 1088 : | ########################################################################## | ||
| 1089 : | |||
| 1090 : | print "<body>\n"; | ||
| 1091 : | print "<img src=img/header.gif>"; | ||
| 1092 : | |||
| 1093 : | print "<h1>"$title</h1>"; | ||
| 1094 : | print "<em>$comment</em>"; | ||
| 1095 : | print "<blockquote>\n"; | ||
| 1096 : | |||
| 1097 : | include $contents; | ||
| 1098 : | |||
| 1099 : | print ("</blockquote>\n"); | ||
| 1100 : | print ("</body>\n"); | ||
| 1101 : | print ("</html>\n"); | ||
| 1102 : | |||
| 1103 : | Variables are easily set by calling PHP code in the form of a CGI | ||
| 1104 : | program from a form. | ||
| 1105 : | |||
| 1106 : | |||
| 1107 : | File: unix.info, Node: PHP and forms, Prev: Embedded PHP, Up: PHP and the web | ||
| 1108 : | |||
| 1109 : | PHP and forms | ||
| 1110 : | ------------- | ||
| 1111 : | |||
| 1112 : | PHP is particularly good at dealing with forms, as a CGI scripting | ||
| 1113 : | langauge. Consider the following form: | ||
| 1114 : | |||
| 1115 : | <html> | ||
| 1116 : | <body> | ||
| 1117 : | <form action="/cgi-bin-scriptalias/spititout.php" method="post"> | ||
| 1118 : | |||
| 1119 : | Name: <input type="text" name="personal[name]"><br> | ||
| 1120 : | Email: <input type="text" name="personal[email]"><br> | ||
| 1121 : | Preferred language: | ||
| 1122 : | <select multiple name="language[]"> | ||
| 1123 : | <option value="English">English | ||
| 1124 : | <option value="Norwegian">Norwegian | ||
| 1125 : | <option value="Gobbledigook">Gobbledigook | ||
| 1126 : | </select> | ||
| 1127 : | |||
| 1128 : | <input type=image src="image.gif" name="sub"> | ||
| 1129 : | |||
| 1130 : | </form> | ||
| 1131 : | </body> | ||
| 1132 : | </html> | ||
| 1133 : | This produces a page into which one types a name and email address | ||
| 1134 : | and chooses a language from a list of three possible choices. When the | ||
| 1135 : | user clicks on a button marked by the file `image.gif' the form is | ||
| 1136 : | posted. Here is a program which unravels the data sent to the CGI | ||
| 1137 : | program: | ||
| 1138 : | |||
| 1139 : | |||
| 1140 : | #!/local/bin/php | ||
| 1141 : | |||
| 1142 : | <?php | ||
| 1143 : | # | ||
| 1144 : | # A CGI program which handles a form | ||
| 1145 : | # Variables a translated automatically | ||
| 1146 : | # | ||
| 1147 : | |||
| 1148 : | $title = "This page title"; | ||
| 1149 : | $comment = "This pages talks about the following....."; | ||
| 1150 : | |||
| 1151 : | ########################################################################## | ||
| 1152 : | |||
| 1153 : | echo "<body>"; | ||
| 1154 : | echo "<h1>$title</h1>"; | ||
| 1155 : | echo "<em>$comment</em>"; | ||
| 1156 : | echo "<blockquote>\n"; | ||
| 1157 : | |||
| 1158 : | ### | ||
| 1159 : | |||
| 1160 : | echo "Your name is $personal[name]<br><br>"; | ||
| 1161 : | echo "Your email is $personal[email]<br><br>"; | ||
| 1162 : | |||
| 1163 : | echo "Language options: "; | ||
| 1164 : | echo "<table> "; | ||
| 1165 : | |||
| 1166 : | for ($i = 0; strlen($language[$i]) > 0; $i++) | ||
| 1167 : | { | ||
| 1168 : | echo "<tr><td bgcolor=#ff0000>Variable language[$i] = $language[$i]</td></tr>"; | ||
| 1169 : | } | ||
| 1170 : | |||
| 1171 : | if ($language[0] == "Norwegian") | ||
| 1172 : | { | ||
| 1173 : | echo "Hei alle sammen<p>"; | ||
| 1174 : | } | ||
| 1175 : | else | ||
| 1176 : | { | ||
| 1177 : | echo "Greetings everyone, this page will be in English<p>"; | ||
| 1178 : | } | ||
| 1179 : | |||
| 1180 : | echo "</table> "; | ||
| 1181 : | |||
| 1182 : | ### | ||
| 1183 : | |||
| 1184 : | echo ("</blockquote>\n"); | ||
| 1185 : | echo ("</body>\n"); | ||
| 1186 : | echo ("</html>\n"); | ||
| 1187 : | ?> | ||
| 1188 : | |||
| 1189 : | |||
| 1190 : | File: unix.info, Node: C programming, Next: Network programming, Prev: WWW and CGI programming, Up: Top | ||
| 1191 : | |||
| 1192 : | C programming | ||
| 1193 : | ************* | ||
| 1194 : | |||
| 1195 : | _This section is not meant to teach you C. It is a guide to using C | ||
| 1196 : | in UNIX and it is assumed that you have a working knowledge of the | ||
| 1197 : | language. See the GNU C-Tutorial for an introduction to basics._ | ||
| 1198 : | |||
| 1199 : | * Menu: | ||
| 1200 : | |||
| 1201 : | * Shell or C?:: | ||
| 1202 : | * C program structure:: | ||
| 1203 : | * UNIX calls and POSIX:: | ||
| 1204 : | * Compiling C:: | ||
| 1205 : | * Make:: | ||
| 1206 : | * argv argc envp:: | ||
| 1207 : | * Environment variables in C:: | ||
| 1208 : | * C files and dirs:: | ||
| 1209 : | * File test macros:: | ||
| 1210 : | * Process control:: | ||
| 1211 : | * A more secure popen:: | ||
| 1212 : | * Traps and signals:: | ||
| 1213 : | * Regular expressions in C:: | ||
| 1214 : | * DES encryption:: | ||
| 1215 : | * ioctl:: | ||
| 1216 : | * Database example in C:: | ||
| 1217 : | * lex and yacc:: | ||
| 1218 : | * Ex 6:: | ||
| 1219 : | |||
| 1220 : | |||
| 1221 : | File: unix.info, Node: Shell or C?, Next: C program structure, Prev: C programming, Up: C programming | ||
| 1222 : | |||
| 1223 : | Shell or C? | ||
| 1224 : | =========== | ||
| 1225 : | |||
| 1226 : | In the preceding chapters we have been looking at ways to get simple | ||
| 1227 : | programming tasks done. The immediateness of the script languages is a | ||
| 1228 : | great advantage when we just want to get a job done as quickly as | ||
| 1229 : | possible. Scripts lend themselves to simple system administration tasks | ||
| 1230 : | like file processing, but they do not easily lend themselves to more | ||
| 1231 : | serious programs. | ||
| 1232 : | |||
| 1233 : | Although some system administrators have grown to the idea that shell | ||
| 1234 : | programming is easier, I would argue that this is not really true. | ||
| 1235 : | First of all, most of the UNIX shell commands are just wrapper programs | ||
| 1236 : | for C function calls. Why use the wrapper when you can use the real | ||
| 1237 : | thing? Secondly, the C function calls return data in pointers and | ||
| 1238 : | structures which are very easy to manipulate, whereas piping the output | ||
| 1239 : | of shell programs into others can be a very messy and awkward way of | ||
| 1240 : | working. Here are some of the reasons why we also need a more | ||
| 1241 : | traditional programming language like C. | ||
| 1242 : | |||
| 1243 : | 1. The shell languages do not allow us to create an acceptable | ||
| 1244 : | user-interface, like X-windows, or the curses (cursor manipulation) | ||
| 1245 : | library. They are mainly intended for file-processing. (Though | ||
| 1246 : | recently the _Tk_ library has provided a way of creating user | ||
| 1247 : | interfaces in Tcl and Perl.) | ||
| 1248 : | |||
| 1249 : | 2. Shell commands read their input line-by-line. Not all input is | ||
| 1250 : | generated in this simple way - we also need to be able to read | ||
| 1251 : | through lines i.e. the concept of a _data stream_. | ||
| 1252 : | |||
| 1253 : | 3. More advanced data structures are needed for most applications, | ||
| 1254 : | such as linked lists and binary trees, acyclic graphs etc. | ||
| 1255 : | |||
| 1256 : | 4. Compilers help to sort out simple typographical and logical errors | ||
| 1257 : | by compile-time checking source code. | ||
| 1258 : | |||
| 1259 : | 5. Compiled code is faster than interpreted code. | ||
| 1260 : | |||
| 1261 : | 6. Many tools have been written to help in the programming of C code | ||
| 1262 : | (dbx, lex, yacc etc.). | ||
| 1263 : | |||
| 1264 : | |||
| 1265 : | |||
| 1266 : | File: unix.info, Node: C program structure, Next: UNIX calls and POSIX, Prev: Shell or C?, Up: C programming | ||
| 1267 : | |||
| 1268 : | C program structure | ||
| 1269 : | =================== | ||
| 1270 : | |||
| 1271 : | * Menu: | ||
| 1272 : | |||
| 1273 : | * C structure:: | ||
| 1274 : | * Macros and declarations:: | ||
| 1275 : | * Several files:: | ||
| 1276 : | |||
| 1277 : | |||
| 1278 : | File: unix.info, Node: C structure, Next: Macros and declarations, Prev: C program structure, Up: C program structure | ||
| 1279 : | |||
| 1280 : | The form of a C program | ||
| 1281 : | ----------------------- | ||
| 1282 : | |||
| 1283 : | A C program consists of a set of function, beginning with the main | ||
| 1284 : | program: | ||
| 1285 : | |||
| 1286 : | |||
| 1287 : | main () /* This is a comment */ | ||
| 1288 : | |||
| 1289 : | { | ||
| 1290 : | |||
| 1291 : | Commands ... | ||
| 1292 : | |||
| 1293 : | |||
| 1294 : | } | ||
| 1295 : | |||
| 1296 : | The source code of a C program can be divided into several text | ||
| 1297 : | files. C compiles all functions separately; the linker `ld' joins them | ||
| 1298 : | all up at the end. This means that we can plan out a strategy for | ||
| 1299 : | writing large programs in a clear and efficient manner. | ||
| 1300 : | |||
| 1301 : | NOTE: C++ style comments `//...' are not allowed by most C compilers. | ||
| 1302 : | |||
| 1303 : | |||
| 1304 : | File: unix.info, Node: Macros and declarations, Next: Several files, Prev: C structure, Up: C program structure | ||
| 1305 : | |||
| 1306 : | Macros and declarations | ||
| 1307 : | ----------------------- | ||
| 1308 : | |||
| 1309 : | Most Unix systems now have ANSI C compatible compilers, but this has | ||
| 1310 : | not always been the case. Most UNIX programs written in a version of C | ||
| 1311 : | which is older than the ANSI standard, so you will need an appreciation | ||
| 1312 : | of old Kernighan and Ritchie C conventions for C programming. See for | ||
| 1313 : | example my C book. | ||
| 1314 : | |||
| 1315 : | An obvious difference between ANSI C and K&R C is that the C++ | ||
| 1316 : | additions to the language are not included. Here are some useful points | ||
| 1317 : | to remember. | ||
| 1318 : | |||
| 1319 : | * K&R C does not allow `const' data, it uses the C preprocessor with | ||
| 1320 : | `#define' instead. i.e. intead of | ||
| 1321 : | |||
| 1322 : | const int blah = 1; | ||
| 1323 : | |||
| 1324 : | use | ||
| 1325 : | #define blah 1 | ||
| 1326 : | |||
| 1327 : | Remember that the hash symbol `#' must be the first character on a | ||
| 1328 : | line under UNIX. | ||
| 1329 : | |||
| 1330 : | * K&R C doesn't use function prototypes or declarations of the form: | ||
| 1331 : | |||
| 1332 : | void function (char *string, int a, int b) | ||
| 1333 : | |||
| 1334 : | { | ||
| 1335 : | } | ||
| 1336 : | |||
| 1337 : | Instead one writes: | ||
| 1338 : | |||
| 1339 : | void function (string, a, b) | ||
| 1340 : | |||
| 1341 : | char *string; | ||
| 1342 : | int a,b; | ||
| 1343 : | |||
| 1344 : | { | ||
| 1345 : | } | ||
| 1346 : | |||
| 1347 : | |||
| 1348 : | File: unix.info, Node: Several files, Prev: Macros and declarations, Up: C program structure | ||
| 1349 : | |||
| 1350 : | Several files | ||
| 1351 : | ------------- | ||
| 1352 : | |||
| 1353 : | Most unix programs are very large and are split up into many files. | ||
| 1354 : | Remember, when you split up programs into several files, you must | ||
| 1355 : | declare variables as `extern' in file A if they are really declared in | ||
| 1356 : | file B. in which you want to use them. This tells the compiler that it | ||
| 1357 : | should not try to create local storage for the variable, because this | ||
| 1358 : | was already done in another file. | ||
| 1359 : | |||
| 1360 : | |||
| 1361 : | File: unix.info, Node: UNIX calls and POSIX, Next: Compiling C, Prev: C program structure, Up: C programming | ||
| 1362 : | |||
| 1363 : | A note about UNIX system calls and standards | ||
| 1364 : | ============================================ | ||
| 1365 : | |||
| 1366 : | Most of the system calls in UNIX return data in the form of `struct' | ||
| 1367 : | variables. Sometimes these are structures used by the operating system | ||
| 1368 : | itself - in other cases they are just put together so that programmers | ||
| 1369 : | can handle a packet of data in a convenient way. | ||
| 1370 : | |||
| 1371 : | If in doubt, you can find the definitions of these structures in the | ||
| 1372 : | relevant include files under `/usr/include'. | ||
| 1373 : | |||
| 1374 : | Since UNIX comes in many flavours the system calls are not always | ||
| 1375 : | compatible and may have different options and arguments. Because of | ||
| 1376 : | this there is a number of standardizing organizations for UNIX. One of | ||
| 1377 : | them is POSIX which is an organization run by the major UNIX vendors. | ||
| 1378 : | Programs written for UNIX are now expected to be POSIX compliant. This | ||
| 1379 : | is not something you need to think about at the level of this course, | ||
| 1380 : | but you should certainly remember that there exist programming | ||
| 1381 : | standards and that these should be adhered to. The aim is to work | ||
| 1382 : | towards a single standard UNIX. | ||
| 1383 : | |||
| 1384 : | |||
| 1385 : | File: unix.info, Node: Compiling C, Next: Make, Prev: UNIX calls and POSIX, Up: C programming | ||
| 1386 : | |||
| 1387 : | Compiling: `cc', `ld' and `a.out' | ||
| 1388 : | ================================= | ||
| 1389 : | |||
| 1390 : | The C compiler on the unix system is traditionally called `cc' and | ||
| 1391 : | has always been a traditional part of every Unix environment. Recently | ||
| 1392 : | several Unix vendors have stopped including the C compiler as a part of | ||
| 1393 : | their operating systems and instead sell a compiler separately. | ||
| 1394 : | Fortunately there is a public domain Free Software version of the | ||
| 1395 : | compiler called `gcc' (the GNU C compiler). We shall use this in all | ||
| 1396 : | the examples. | ||
| 1397 : | |||
| 1398 : | To compile a program consisting of several files of code, we first | ||
| 1399 : | compile all of the separate pieces without trying to link them. There | ||
| 1400 : | are therefore two stages: first we turn `.c' files into `.o' files. | ||
| 1401 : | This compiles code but does not fix any address references. Then we | ||
| 1402 : | link all `.o' files into the final executable, including any libraries | ||
| 1403 : | which are used. | ||
| 1404 : | |||
| 1405 : | Let's suppose we have files `a.c', `b.c' and `c.c'. We write: | ||
| 1406 : | |||
| 1407 : | gcc -c a.c b.c c.c | ||
| 1408 : | This creates files `a.o', `b.o' and `c.o'. Next we link them into | ||
| 1409 : | one file called `myprog'. | ||
| 1410 : | |||
| 1411 : | gcc -o myprog a.o b.o c.o | ||
| 1412 : | |||
| 1413 : | If the naming option `-o myprog' is not used, the link `ld' uses the | ||
| 1414 : | default name _a.out_ for the executable file. | ||
| 1415 : | |||
| 1416 : | * Menu: | ||
| 1417 : | |||
| 1418 : | * Libraries and LD_LIBRARY_PATH:: | ||
| 1419 : | * Include files:: | ||
| 1420 : | * Shared and static libraries:: | ||
| 1421 : | * Important paths:: | ||
| 1422 : | |||
| 1423 : | |||
| 1424 : | File: unix.info, Node: Libraries and LD_LIBRARY_PATH, Next: Include files, Prev: Compiling C, Up: Compiling C | ||
| 1425 : | |||
| 1426 : | Libraries and `LD_LIBRARY_PATH' | ||
| 1427 : | ------------------------------- | ||
| 1428 : | |||
| 1429 : | The resulting file is called `myprog' and includes references only | ||
| 1430 : | to the standard library `libc'. If we wish to link in the math library | ||
| 1431 : | `libm' or the cursor movement library `libcurses' - or in general, a | ||
| 1432 : | library called `libBLAH' , we need to use the `-l' directive. | ||
| 1433 : | |||
| 1434 : | |||
| 1435 : | gcc -o myprog files.o -lm -lcurses -lBLAH | ||
| 1436 : | |||
| 1437 : | The compiler looks for a suitable library in all of the directories | ||
| 1438 : | listed in the environment variable `LD_LIBRARY_PATH'. Alternatively we | ||
| 1439 : | can add a directory to the search path by using the `-L'. option: | ||
| 1440 : | |||
| 1441 : | gcc -o myprog files.o -L/usr/local/lib -lm -lcurses -lBLAH | ||
| 1442 : | |||
| 1443 : | |||
| 1444 : | File: unix.info, Node: Include files, Next: Shared and static libraries, Prev: Libraries and LD_LIBRARY_PATH, Up: Compiling C | ||
| 1445 : | |||
| 1446 : | Include files | ||
| 1447 : | ------------- | ||
| 1448 : | |||
| 1449 : | Normally the compiler looks for include files only in the directory | ||
| 1450 : | `/usr/include'. We can add further paths to search using the `-I' | ||
| 1451 : | option. | ||
| 1452 : | |||
| 1453 : | gcc -o myprog file.c -I/usr/local/include -I/usr/local/X11/include | ||
| 1454 : | |||
| 1455 : | Previously, Unix libraries have been in `a.out' code format, but | ||
| 1456 : | recent releases of unix have gone over to a more efficient and flexible | ||
| 1457 : | format called ELF (executable and linking format). | ||
| 1458 : | |||
| 1459 : | |||
| 1460 : | File: unix.info, Node: Shared and static libraries, Next: Important paths, Prev: Include files, Up: Compiling C | ||
| 1461 : | |||
| 1462 : | Shared and static libraries | ||
| 1463 : | --------------------------- | ||
| 1464 : | |||
| 1465 : | Libraries are collections of C functions which the operating system | ||
| 1466 : | creators have written for our convenience. The source code for such a | ||
| 1467 : | library is just the source for a collection of functions - there is no | ||
| 1468 : | `main' program. | ||
| 1469 : | |||
| 1470 : | There are two kinds of library used by modern operating systems: | ||
| 1471 : | _archive libraries_ or static libraries and `shared libraries' or | ||
| 1472 : | dynamical libraries. An archive library has a name of the form | ||
| 1473 : | |||
| 1474 : | libNAME.a | ||
| 1475 : | |||
| 1476 : | When an archive library is linked to a program, it is appended lock, | ||
| 1477 : | stock and barrel to the program code. This uses a lot of disk space and | ||
| 1478 : | makes the size of the compiled program very large. Shared libraries | ||
| 1479 : | (shared objects `so' or shared archives `sa' generally have names of | ||
| 1480 : | the form) | ||
| 1481 : | |||
| 1482 : | libNAME.so | ||
| 1483 : | libNAME.sa | ||
| 1484 : | |||
| 1485 : | often with version numbers appended. When a program is linked with a | ||
| 1486 : | shared library the code is not appended to the program. Instead | ||
| 1487 : | pointers to the shared objects are created and the library is loaded at | ||
| 1488 : | runtime, thus avoiding the problem of having to store the library | ||
| 1489 : | effectively multiple times on the disk. | ||
| 1490 : | |||
| 1491 : | To make an archive library we compile all of the functions we wish | ||
| 1492 : | to include in the library | ||
| 1493 : | |||
| 1494 : | |||
| 1495 : | gcc -c function1.c function2.c ... | ||
| 1496 : | |||
| 1497 : | and then join the files using the `ar' command. | ||
| 1498 : | |||
| 1499 : | |||
| 1500 : | ar rcv libMYLIB.a function1.o | ||
| 1501 : | ar rcv libMYLIB.a function2.o | ||
| 1502 : | |||
| 1503 : | To make a shared library one provides an option to the linker program. | ||
| 1504 : | The exact method is different in different operating systems, so you | ||
| 1505 : | should look at the manual page for `ld' on your system. Under SunOS 4 | ||
| 1506 : | we take the object files `*.o' and run | ||
| 1507 : | |||
| 1508 : | ld -o libMYLIB.so.1.1 -assert pure-text *.o | ||
| 1509 : | Under HPUX, we write | ||
| 1510 : | |||
| 1511 : | ld -b -o libMYLIB.so.1.1 *.o | ||
| 1512 : | With the GNU linker, you write | ||
| 1513 : | |||
| 1514 : | ld -shared -o libMYLIB.so.1.1 *.o | ||
| 1515 : | |||
| 1516 : | NOTE: when you add a shared library to the system under SunOS or | ||
| 1517 : | GNU/Linux you must run the command `ldconfig', making sure that the | ||
| 1518 : | path to the library is included in `LD_LIBRARY_PATH'. SunOS and | ||
| 1519 : | GNU/Linux use a cache file `/etc/ld.so.cache' to keep current versions | ||
| 1520 : | of libraries. GNU/Linux also uses a configuration file called | ||
| 1521 : | `/etc/ld.so.conf'. | ||
| 1522 : | |||
| 1523 : | |||
| 1524 : | File: unix.info, Node: Important paths, Prev: Shared and static libraries, Up: Compiling C | ||
| 1525 : | |||
| 1526 : | Knowing about important paths: directory structure | ||
| 1527 : | -------------------------------------------------- | ||
| 1528 : | |||
| 1529 : | It is important to understand how the C compiler finds the files it | ||
| 1530 : | needs. We have already mentioned the `-I' and `-L' options to the | ||
| 1531 : | compilation command line. In general, all system include files can be | ||
| 1532 : | found in the directory `/usr/include' and subdirectories of this | ||
| 1533 : | directory. All system libraries can be found in `/usr/lib'. | ||
| 1534 : | |||
| 1535 : | Many packages build their own libraries and keep the relevant files | ||
| 1536 : | in separate directories so that if the system gets reinstalled, they do | ||
| 1537 : | not get deleted. This is true for example of the X-windows system. The | ||
| 1538 : | include and library files for this are typically kept in directories | ||
| 1539 : | which look something like `/usr/local/X11R5/include' and | ||
| 1540 : | `/usr/X11R6/lib'. That means that we need to give all of this | ||
| 1541 : | information to the compiler. Compiling a program becomes a complicated | ||
| 1542 : | task in many cases so we need some kind of script to help us perform | ||
| 1543 : | the task. The Unix tool `make' was designed for this purpose. | ||
| 1544 : | |||
| 1545 : | |||
| 1546 : | File: unix.info, Node: Make, Next: argv argc envp, Prev: Compiling C, Up: C programming | ||
| 1547 : | |||
| 1548 : | Make | ||
| 1549 : | ==== | ||
| 1550 : | |||
| 1551 : | Nowadays compilers are often sold with fancy user environments | ||
| 1552 : | driven by menus which make it easier to compile programs. Unix has | ||
| 1553 : | similar environments but all of them use shell-based command line | ||
| 1554 : | compilation beneath the surface. That is because UNIX programmers are | ||
| 1555 : | used to writing large and complex programs which occupy many | ||
| 1556 : | directories and subdirectories. Each directory has to be adapted or | ||
| 1557 : | configured to fit the particular flavour of Unix system it is being | ||
| 1558 : | compiled upon. Interactive user environments are very poor at | ||
| 1559 : | performing this kind of service. UNIX solves the problem of compiling | ||
| 1560 : | enormous _trees_ of software (such as the unix system itself!) by using | ||
| 1561 : | a compilation language called `make'. Such language files can be | ||
| 1562 : | generated automatically by scripts, allowing very complex programs to | ||
| 1563 : | configure and compile themselves from a single control script. | ||
| 1564 : | |||
| 1565 : | * Menu: | ||
| 1566 : | |||
| 1567 : | * Compiling large programs:: | ||
| 1568 : | * Makefiles:: | ||
| 1569 : | * Suffix rules for C++:: | ||
| 1570 : |
| Administrator | ViewVC Help |
| Powered by ViewVC 1.0.3 |