Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

filemem.cc

Go to the documentation of this file.
00001 /************************************************************************
00002 File: FILEMEM.cc
00003 Purpose: Provides a derived class of CMS that reads and writes
00004 messages to a plain text file. The file size can be limited from
00005 the NML configuration file.
00006 **********************************************************************/
00007 
00008 /*
00009   Modification history:
00010 
00011   18-Oct-1996  FMP added fgetpos(), fsetpos() for LynxOS, since it doesn't
00012   have it
00013   ??? Will Shackleford created, but who knows when since he doesn't use
00014   modification histories. Bad boy.
00015 */
00016 
00017 #include "rcs_defs.hh"          // EXTERN_C_STD_HEADERS
00018 #include "filemem.hh"           // class FILEMEM
00019 #include "cms.hh"               // class CMS
00020 #include "rcs_prnt.hh"          // rcs_print_error()
00021 #include "timer.hh"             // etime()
00022 
00023 #ifdef EXTERN_C_STD_HEADERS
00024 extern "C"
00025 {
00026 #endif
00027 
00028 #include <stdlib.h>             // malloc()
00029 #include <string.h>             // strcpy(), strcmp()
00030 #include <errno.h>              // errno
00031 
00032 
00033 #ifdef  USE_FCNTL_FILE_LOCKING
00034 #include <fcntl.h>
00035 #endif
00036 
00037 #if defined(USE_FCNTL_FILE_LOCKING) && defined(FILEMEM_USE_SEMAPHORES)
00038 #error Can not compile with both defined(USE_FCNTL_FILE_LOCKING && FILEMEM_USE_SEMAPHORES)
00039 #endif
00040 
00041 #if defined(lynxosPC) || defined(sunos4)
00042 
00043 // no prototypes for these in LynxOS-- how lame. Let's do them here
00044 
00045 #include <stdio.h>              /* ftell(), fpos_t */
00046 #include <unistd.h>             // SEEK_SET
00047 
00048   static int fgetpos (FILE * stream, fpos_t * ptr);
00049   static int fsetpos (FILE * stream, const fpos_t * ptr);
00050 
00051 // FIXME-- test these!
00052 
00053   int fgetpos (FILE * stream, fpos_t * ptr)
00054   {
00055     long retval;
00056 
00057       retval = ftell (stream);
00058 
00059     if (retval == -1L)
00060       {
00061         return -1;
00062       }
00063     else
00064       {
00065         *ptr = (fpos_t) retval;
00066         return 0;
00067       }
00068   }
00069 
00070   int fsetpos (FILE * stream, const fpos_t * ptr)
00071   {
00072     return fseek (stream, (long) *ptr, SEEK_SET);
00073   }
00074 
00075 #endif
00076 
00077 #ifdef EXTERN_C_STD_HEADERS
00078 }
00079 #endif
00080 
00081 /* rw-rw-r-- permissions */
00082 #ifndef WIN32
00083 #define MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
00084 #else
00085 #define MODE (0)
00086 #endif
00087 
00088 // Sunos4 header files are missing SEEK_SET
00089 #if defined(sunos4) && !defined(SEEK_SET)
00090 #define SEEK_SET 0
00091 #endif
00092 
00093 
00094 FILEMEM::FILEMEM (char *bufline, char *procline, int set_to_server,
00095                   int set_to_master):
00096 CMS (bufline, procline, set_to_server)
00097 {
00098   char *infile_name_string = (char *) NULL;
00099   char *outfile_name_string = (char *) NULL;
00100   char *end_name = (char *) NULL;
00101 
00102   int master;
00103   master = is_local_master;
00104   if (1 == set_to_master)
00105     {
00106       master = 1;
00107     }
00108   else if (-1 == set_to_master)
00109     {
00110       master = 0;
00111     }
00112 
00113   in = (FILE *) NULL;
00114   out = (FILE *) NULL;
00115   write_time = 0;
00116   last_write_time = 0;
00117   read_time = 0;
00118   last_read_time = 0;
00119   wait_period = 0;
00120   wait_start = 0;
00121   write_count = 0;
00122   write_cycle = 0;
00123   read_cycle = 0;
00124   add_waits = 0;
00125   write_file_length = 0;
00126   input_is_stdin = 0;
00127   output_is_stdout = 0;
00128 
00129   if (CMS_DISPLAY_ASCII_ENCODING != neutral_encoding_method || !neutral)
00130     {
00131       rcs_print_error
00132         ("The neutral_encoding_method must be ASCII_DISPLAY_ENCODING and the buffer must be neutral format to use FILEMEM.\n");
00133       status = CMS_CONFIG_ERROR;
00134     }
00135 
00136 #ifdef FILEMEM_USE_SEMAPHORES
00137   /* Save parameters from configuration file. */
00138   if (sscanf (bufline, "%*s %*s %*s %*s %*d %*s %*s %*d %d", &key) != 1)
00139     {
00140       rcs_print_error ("FILEMEM: Invalid configuration file format.\n");
00141       return;
00142     }
00143 #endif
00144 
00145   if (NULL != strstr (procline, "add_waits")
00146       || NULL != strstr (bufline, "add_waits"))
00147     {
00148       add_waits = 1;
00149     }
00150 
00151 
00152   outfile_name_string = strstr (procline, "out=");
00153   if (NULL == outfile_name_string)
00154     {
00155       outfile_name_string = strstr (bufline, "out=");
00156     }
00157   if (NULL != outfile_name_string)
00158     {
00159       strcpy (outfile_name, outfile_name_string + 4);
00160       end_name = strpbrk (outfile_name, " \t\n\r,;=");
00161       if (NULL != end_name)
00162         {
00163           *end_name = 0;
00164         }
00165       if (!strcmp (outfile_name, "stdout"))
00166         {
00167           output_is_stdout = 1;
00168           out = stdout;
00169         }
00170       else
00171         {
00172           out = fopen (outfile_name, "w+");
00173           if (out == NULL || ((long) out) == -1)
00174             {
00175               rcs_print_error ("FILEMEM: Can not open %s. (error = %d,%s)\n",
00176                                outfile_name, errno, strerror (errno));
00177               status = CMS_CREATE_ERROR;
00178               return;
00179             }
00180         }
00181     }
00182   else
00183     {
00184       strcpy (outfile_name, "stdout");
00185       output_is_stdout = 1;
00186       out = stdout;
00187     }
00188 
00189   infile_name_string = strstr (procline, "in=");
00190   if (NULL == infile_name_string)
00191     {
00192       infile_name_string = strstr (bufline, "in=");
00193     }
00194   if (NULL != infile_name_string)
00195     {
00196       strcpy (infile_name, infile_name_string + 3);
00197 
00198       end_name = strpbrk (infile_name, " \t\n\r,;=");
00199       if (NULL != end_name)
00200         {
00201           *end_name = 0;
00202         }
00203       if (!strcmp (infile_name, "stdin"))
00204         {
00205           in = stdin;
00206         }
00207       else
00208         {
00209           in = fopen (infile_name, "r");
00210           if (in == NULL || ((long) in) == -1)
00211             {
00212               rcs_print_error ("FILEMEM: Can not open %s. (error = %d,%s)\n",
00213                                infile_name, errno, strerror (errno));
00214               status = CMS_CREATE_ERROR;
00215               return;
00216             }
00217         }
00218     }
00219   else
00220     {
00221       strcpy (infile_name, "stdin");
00222       in = stdin;
00223     }
00224 
00225   max_output_messages = -1;
00226   char *ptr;
00227   ptr = strstr (procline, "max_out=");
00228   if (NULL == ptr)
00229     {
00230       ptr = strstr (bufline, "max_out=");
00231     }
00232   if (NULL != ptr)
00233     {
00234       max_output_messages = strtol (ptr + 8, (char **) NULL, 0);
00235     }
00236 
00237 #ifdef FILEMEM_USE_SEMAPHORES
00238   if (is_local_master)
00239     {
00240       sem = new RCS_SEMAPHORE (key, RCS_SEMAPHORE_CREATE, -1, (int) MODE, 1);
00241       if (NULL == sem)
00242         {
00243           rcs_print_error ("CMS: couldn't create RCS_SEMAPHORE.\n");
00244           rcs_print_error (" Possibly out of memory?\n");
00245           status = CMS_CREATE_ERROR;
00246           return;
00247         }
00248       if (!sem->valid ())
00249         {
00250           rcs_print_error ("CMS: RCS_SEMAPHORE is invalid.\n");
00251           status = CMS_MISC_ERROR;
00252           return;
00253         }
00254     }
00255   else
00256     {
00257       sem = new RCS_SEMAPHORE (key, RCS_SEMAPHORE_NOCREATE, -1);
00258       if (NULL == sem)
00259         {
00260           rcs_print_error ("CMS: couldn't create RCS_SEMAPHORE.\n");
00261           rcs_print_error (" Possibly out of memory?\n");
00262           status = CMS_CREATE_ERROR;
00263           return;
00264         }
00265       if (!sem->valid ())
00266         {
00267           rcs_print_error ("CMS: RCS_SEMAPHORE is invalid.\n");
00268           status = CMS_MISC_ERROR;
00269           return;
00270         }
00271     }
00272 #endif
00273 
00274 
00275 
00276   fgetpos (in, &last_read_pos);
00277   fgetpos (out, &last_write_pos);
00278 
00279 }
00280 
00281 
00282 FILEMEM::~FILEMEM ()
00283 {
00284   if (NULL != in && strcmp (infile_name, "stdin"))
00285     {
00286       fclose (in);
00287       in = (FILE *) NULL;
00288     }
00289   if (NULL != out && strcmp (outfile_name, "stdout"))
00290     {
00291       fclose (out);
00292       out = (FILE *) NULL;
00293     }
00294 #ifdef FILEMEM_USE_SEMAPHORES
00295   if (NULL != sem)
00296     {
00297       if (is_local_master || delete_totally)
00298         {
00299           sem->setflag (RCS_SEMAPHORE_CREATE);
00300         }
00301       else
00302         {
00303           sem->setflag (RCS_SEMAPHORE_NOCREATE);
00304         }
00305       delete sem;
00306       sem = (RCS_SEMAPHORE *) NULL;
00307     }
00308 #endif
00309 
00310 }
00311 
00312 CMS_STATUS
00313 FILEMEM::clear ()
00314 {
00315   return status;
00316 }
00317 
00318 int
00319 FILEMEM::check_if_read ()
00320 {
00321   return 1;
00322 }
00323 
00324 CMS_STATUS
00325 FILEMEM::read ()
00326 {
00327   char *ptr;
00328   read_time = etime ();
00329   if (read_time - wait_start < wait_period && last_read_time > 0
00330       && wait_start > 0)
00331     {
00332       return (status = CMS_READ_OLD);
00333     }
00334   wait_period = 0;
00335   if (NULL == in)
00336     {
00337       reopen_input ();
00338     }
00339 
00340   if (NULL == in)
00341     {
00342       rcs_print_error ("FILE *in=NULL\n");
00343       return (status = CMS_MISC_ERROR);
00344     }
00345   if (lock_input () < 0)
00346     {
00347       return (status = CMS_MISC_ERROR);
00348     }
00349 
00350   while (!feof (in))
00351     {
00352       memset (input_buffer, 0, FILEMEM_INPUT_BUFFER_SIZE);
00353       fgetpos (in, &last_read_pos);
00354       fgets (input_buffer, FILEMEM_INPUT_BUFFER_SIZE, in);
00355       if (!strncmp (input_buffer, "MSG", 3))
00356         {
00357           ptr = strstr (input_buffer, ">");
00358           if (NULL == ptr)
00359             {
00360               rcs_print_error ("FILEMEM: Badly formatted message string.\n");
00361               unlock_input ();
00362               return (status = CMS_MISC_ERROR);
00363             }
00364           if (0 == *ptr)
00365             {
00366               rcs_print_error ("FILEMEM: Badly formatted message string.\n");
00367               unlock_input ();
00368               return (status = CMS_MISC_ERROR);
00369             }
00370           strcpy ((char *) encoded_data, ptr + 1);
00371           last_read_time = read_time;
00372           unlock_input ();
00373           close_input ();
00374           return (status = CMS_READ_OK);
00375         }
00376       if (!strncmp (input_buffer, "WAIT", 4))
00377         {
00378           ptr = strstr (input_buffer, ">");
00379           if (NULL == ptr)
00380             {
00381               rcs_print_error ("FILEMEM: Badly formatted message string.\n");
00382               unlock_input ();
00383               return (status = CMS_MISC_ERROR);
00384             }
00385           if (0 == *ptr)
00386             {
00387               rcs_print_error ("FILEMEM: Badly formatted message string.\n");
00388               return (status = CMS_MISC_ERROR);
00389             }
00390           errno = 0;
00391           wait_period = strtod (ptr + 1, (char **) NULL);
00392           if (errno != 0)
00393             {
00394               rcs_print_error ("FILEMEM: Badly formatted message string.\n");
00395               unlock_input ();
00396               return (status = CMS_MISC_ERROR);
00397             }
00398           wait_start = last_read_time;
00399           if (read_time - wait_start < wait_period && last_read_time > 0
00400               && wait_start > 0)
00401             {
00402               unlock_input ();
00403               close_input ();
00404               return (status = CMS_READ_OLD);
00405             }
00406           last_read_time = read_time;
00407         }
00408       if (!strncmp (input_buffer, "REWIND", 5))
00409         {
00410           fseek (in, 0, SEEK_SET);
00411         }
00412       if (!strncmp (input_buffer, "END", 3))
00413         {
00414           fsetpos (in, &last_read_pos);
00415           unlock_input ();
00416           close_input ();
00417           return (status = CMS_READ_OLD);
00418         }
00419     }
00420   unlock_input ();
00421   close_input ();
00422   last_read_time = read_time;
00423   return (status = CMS_READ_OLD);
00424 }
00425 
00426 int
00427 FILEMEM::lock_input ()
00428 {
00429   if (input_is_stdin)
00430     {
00431       return 0;
00432     }
00433 #ifdef FILEMEM_USE_SEMAPHORES
00434   if (NULL == sem)
00435     {
00436       return -1;
00437     }
00438   return sem->wait ();
00439 #endif
00440 
00441 
00442 #ifdef USE_FCNTL_FILE_LOCKING
00443   input_fd = fileno (in);
00444   read_lock.l_type = F_RDLCK;
00445   read_lock.l_start = 0;
00446   read_lock.l_whence = SEEK_SET;
00447   read_lock.l_len = 0;
00448   while (1)
00449     {
00450       switch (fcntl (input_fd, F_SETLK, &read_lock))
00451         {
00452         case -1:
00453           if (errno == EACCES || errno == EAGAIN)
00454             {
00455               continue;
00456             }
00457           rcs_print_error
00458             ("FILEMEM: Can not lock input file %s. (errno = %d) %s\n",
00459              infile_name, errno, strerror (errno));
00460           return -1;
00461         default:
00462           return 0;
00463         }
00464     }
00465 #endif
00466   return 0;
00467 }
00468 
00469 int
00470 FILEMEM::unlock_input ()
00471 {
00472   if (input_is_stdin)
00473     {
00474       return 0;
00475     }
00476 #ifdef FILEMEM_USE_SEMAPHORES
00477   sem->post ();
00478   return 0;
00479 #endif
00480 
00481 #ifdef USE_FCNTL_FILE_LOCKING
00482   read_lock.l_type = F_UNLCK;
00483   fcntl (input_fd, F_SETLK, &read_lock);
00484 #endif
00485   return 0;
00486 }
00487 
00488 int
00489 FILEMEM::lock_output ()
00490 {
00491   if (output_is_stdout)
00492     {
00493       return 0;
00494     }
00495 
00496 #ifdef FILEMEM_USE_SEMAPHORES
00497   if (NULL == sem)
00498     {
00499       return -1;
00500     }
00501   return sem->wait ();
00502 #endif
00503 
00504 #ifdef USE_FCNTL_FILE_LOCKING
00505   output_fd = fileno (out);
00506   write_lock.l_type = F_WRLCK;
00507   write_lock.l_start = 0;
00508   write_lock.l_whence = SEEK_SET;
00509   write_lock.l_len = 0;
00510   while (1)
00511     {
00512       switch (fcntl (output_fd, F_SETLK, &write_lock))
00513         {
00514         case -1:
00515           if (errno == EACCES || errno == EAGAIN)
00516             {
00517               continue;
00518             }
00519           rcs_print_error
00520             ("FILEMEM: Can not lock input file %s. (errno = %d) %s\n",
00521              infile_name, errno, strerror (errno));
00522           return -1;
00523         default:
00524           return 0;
00525         }
00526     }
00527 #endif
00528   return 0;
00529 }
00530 
00531 int
00532 FILEMEM::unlock_output ()
00533 {
00534   if (output_is_stdout)
00535     {
00536       return 0;
00537     }
00538 #ifdef FILEMEM_USE_SEMAPHORES
00539   sem->post ();
00540   return 0;
00541 #endif
00542 
00543 #ifdef USE_FCNTL_FILE_LOCKING
00544   write_lock.l_type = F_UNLCK;
00545   fcntl (output_fd, F_SETLK, &write_lock);
00546 #endif
00547   return 0;
00548 }
00549 
00550 
00551 CMS_STATUS
00552 FILEMEM::peek ()
00553 {
00554   return read ();
00555 }
00556 
00557 void
00558 FILEMEM::close_input ()
00559 {
00560   if (NULL != in && strcmp (infile_name, "stdin"))
00561     {
00562       input_file_pos = ftell (in);
00563       fseek (in, 0, SEEK_SET);
00564       fgets (input_buffer, FILEMEM_INPUT_BUFFER_SIZE, in);
00565       if (!strncmp (input_buffer, "CYCLE", 5))
00566         {
00567           char *ptr;
00568           long file_cycle;
00569           ptr = strstr (input_buffer, ">");
00570           file_cycle = strtol (ptr + 1, (char **) NULL, 0);
00571           if (file_cycle != read_cycle)
00572             {
00573               read_cycle = file_cycle;
00574               fgetpos (in, &last_read_pos);
00575               return;
00576             }
00577         }
00578       fclose (in);
00579       in = (FILE *) NULL;
00580     }
00581 }
00582 
00583 void
00584 FILEMEM::reopen_input ()
00585 {
00586   if (NULL == in)
00587     {
00588       if (!strcmp (infile_name, "stdin"))
00589         {
00590           in = stdin;
00591         }
00592       else
00593         {
00594           in = fopen (infile_name, "r");
00595           if ((long) in == -1 || in == NULL)
00596             {
00597               in = (FILE *) NULL;
00598               return;
00599             }
00600           fgets (input_buffer, FILEMEM_INPUT_BUFFER_SIZE, in);
00601           if (!strncmp (input_buffer, "CYCLE", 5))
00602             {
00603               char *ptr;
00604               long file_cycle;
00605               ptr = strstr (input_buffer, ">");
00606               file_cycle = strtol (ptr + 1, (char **) NULL, 0);
00607               if (file_cycle > read_cycle)
00608                 {
00609                   read_cycle = file_cycle;
00610                   fgetpos (in, &last_read_pos);
00611                   return;
00612                 }
00613             }
00614           fseek (in, input_file_pos, SEEK_SET);
00615         }
00616     }
00617 }
00618 
00619 CMS_STATUS
00620 FILEMEM::write (void *user_data)
00621 {
00622   char temp_buffer[2048];
00623   long current_pos;
00624   long dist_to_end;
00625   long output_size;
00626 
00627   if (NULL == out)
00628     {
00629       rcs_print_error ("FILE *out=NULL\n");
00630       return (status = CMS_MISC_ERROR);
00631     }
00632   if (lock_output () < 0)
00633     {
00634       return (status = CMS_MISC_ERROR);
00635     }
00636   write_time = etime ();
00637   write_count++;
00638   fsetpos (out, &last_write_pos);
00639   if (write_count > max_output_messages &&
00640       max_output_messages > 0 && strcmp (outfile_name, "stdout") != 0)
00641     {
00642       write_count = 0;
00643       write_cycle++;
00644       fprintf (out, "\nREWIND>%d\n", write_cycle);
00645       current_pos = ftell (out);
00646       if (current_pos > write_file_length)
00647         {
00648           write_file_length = current_pos;
00649         }
00650       dist_to_end = write_file_length - current_pos;
00651       if (dist_to_end > 0)
00652         {
00653           output_size = dist_to_end < 2048 ? dist_to_end : 2048;
00654           if (output_size <= 0)
00655             {
00656               rcs_print_error ("FILEMEM: Bad output size %d.\n", output_size);
00657               unlock_output ();
00658               return (status = CMS_MISC_ERROR);
00659             }
00660           size_t unsigned_output_size = (size_t) output_size;
00661           memset (temp_buffer, '#', output_size);
00662           size_t fwrite_ret = fwrite (temp_buffer, 1, output_size, out);
00663           if (fwrite_ret < unsigned_output_size)
00664             {
00665               rcs_print_error
00666                 ("FILEMEM: Can not write to %s. (error = %d,%s)\n",
00667                  outfile_name, errno, strerror (errno));
00668               unlock_output ();
00669               return (status = CMS_MISC_ERROR);
00670             }
00671         }
00672       fseek (out, 0, SEEK_SET);
00673       if (fprintf
00674           (out,
00675            "CYCLE>%d\n# Returned to the beginning of the file after %d messages.\n",
00676            write_cycle, (int) (write_cycle * max_output_messages)) < 0)
00677         {
00678           rcs_print_error ("FILEMEM: Can not write to %s. (error = %d,%s)\n",
00679                            outfile_name, errno, strerror (errno));
00680           unlock_output ();
00681           return (status = CMS_MISC_ERROR);
00682         }
00683       fgetpos (out, &last_write_pos);
00684 
00685     }
00686   if (fprintf (out, "\n# time=%f, count=%d, cycle=%d",
00687                write_time, write_count, write_cycle) < 0)
00688     {
00689       rcs_print_error ("FILEMEM: Can not write to %s. (error = %d,%s)\n",
00690                        outfile_name, errno, strerror (errno));
00691       unlock_output ();
00692       return (status = CMS_MISC_ERROR);
00693     }
00694   if (add_waits)
00695     {
00696       if (fprintf (out, "\nWAIT> %f",
00697                    last_write_time > 0 ? write_time - last_write_time : 0.0) <
00698           0)
00699         {
00700           rcs_print_error ("FILEMEM: Can not write to %s. (error = %d,%s)\n",
00701                            outfile_name, errno, strerror (errno));
00702           unlock_output ();
00703           return (status = CMS_MISC_ERROR);
00704         }
00705     }
00706   if (fprintf (out, "\nMSG>%s", (char *) encoded_data) < 0)
00707     {
00708       rcs_print_error ("FILEMEM: Can not write to %s. (error = %d,%s)\n",
00709                        outfile_name, errno, strerror (errno));
00710       unlock_output ();
00711       return (status = CMS_MISC_ERROR);
00712     }
00713   last_write_time = write_time;
00714 
00715   fgetpos (out, &last_write_pos);
00716   if (fprintf (out, "\nEND>\n#") < 0)
00717     {
00718       rcs_print_error ("FILEMEM: Can not write to %s. (error = %d,%s)\n",
00719                        outfile_name, errno, strerror (errno));
00720       unlock_output ();
00721       return (status = CMS_MISC_ERROR);
00722     }
00723   current_pos = ftell (out);
00724   if (current_pos > write_file_length)
00725     {
00726       write_file_length = current_pos;
00727     }
00728   if (fflush (out))
00729     {
00730       rcs_print_error ("FILEMEM: Error Flushing output buffer.\n",
00731                        outfile_name, errno, strerror (errno));
00732       unlock_output ();
00733       return (status = CMS_MISC_ERROR);
00734     }
00735   unlock_output ();
00736   return (status = CMS_WRITE_OK);
00737 }
00738 
00739 CMS_STATUS
00740 FILEMEM::write_if_read (void *user_data)
00741 {
00742   return write (user_data);
00743 }

Generated on Sun Dec 2 15:56:49 2001 for rcslib by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001