cbf_write.c

Go to the documentation of this file.
00001 /**********************************************************************
00002  * cbf_write -- write files                                           *
00003  *                                                                    *
00004  * Version 0.6 13 January 1999                                        *
00005  *                                                                    *
00006  *            Paul Ellis (ellis@ssrl.slac.stanford.edu) and           *
00007  *         Herbert J. Bernstein (yaya@bernstein-plus-sons.com)        *
00008  **********************************************************************/
00009   
00010 /**********************************************************************
00011  *                               NOTICE                               *
00012  * Creative endeavors depend on the lively exchange of ideas. There   *
00013  * are laws and customs which establish rights and responsibilities   *
00014  * for authors and the users of what authors create.  This notice     *
00015  * is not intended to prevent you from using the software and         *
00016  * documents in this package, but to ensure that there are no         *
00017  * misunderstandings about terms and conditions of such use.          *
00018  *                                                                    *
00019  * Please read the following notice carefully.  If you do not         *
00020  * understand any portion of this notice, please seek appropriate     *
00021  * professional legal advice before making use of the software and    *
00022  * documents included in this software package.  In addition to       *
00023  * whatever other steps you may be obliged to take to respect the     *
00024  * intellectual property rights of the various parties involved, if   *
00025  * you do make use of the software and documents in this package,     *
00026  * please give credit where credit is due by citing this package,     *
00027  * its authors and the URL or other source from which you obtained    *
00028  * it, or equivalent primary references in the literature with the    *
00029  * same authors.                                                      *
00030  *                                                                    *
00031  * Some of the software and documents included within this software   *
00032  * package are the intellectual property of various parties, and      *
00033  * placement in this package does not in any way imply that any       *
00034  * such rights have in any way been waived or diminished.             *
00035  *                                                                    *
00036  * With respect to any software or documents for which a copyright    *
00037  * exists, ALL RIGHTS ARE RESERVED TO THE OWNERS OF SUCH COPYRIGHT.   *
00038  *                                                                    *
00039  * Even though the authors of the various documents and software      *
00040  * found here have made a good faith effort to ensure that the        *
00041  * documents are correct and that the software performs according     *
00042  * to its documentation, and we would greatly appreciate hearing of   *
00043  * any problems you may encounter, the programs and documents any     *
00044  * files created by the programs are provided **AS IS** without any   *
00045  * warranty as to correctness, merchantability or fitness for any     *
00046  * particular or general use.                                         *
00047  *                                                                    *
00048  * THE RESPONSIBILITY FOR ANY ADVERSE CONSEQUENCES FROM THE USE OF    *
00049  * PROGRAMS OR DOCUMENTS OR ANY FILE OR FILES CREATED BY USE OF THE   *
00050  * PROGRAMS OR DOCUMENTS LIES SOLELY WITH THE USERS OF THE PROGRAMS   *
00051  * OR DOCUMENTS OR FILE OR FILES AND NOT WITH AUTHORS OF THE          *
00052  * PROGRAMS OR DOCUMENTS.                                             *
00053  **********************************************************************/
00054  
00055 /**********************************************************************
00056  *                          The IUCr Policy                           *
00057  *                                 on                                 *
00058  *     the Use of the Crystallographic Information File (CIF)         *
00059  *                                                                    *
00060  * The Crystallographic Information File (Hall, Allen & Brown,        *
00061  * 1991) is, as of January 1992, the recommended method for           *
00062  * submitting publications to Acta Crystallographica Section C. The   *
00063  * International Union of Crystallography holds the Copyright on      *
00064  * the CIF, and has applied for Patents on the STAR File syntax       *
00065  * which is the basis for the CIF format.                             *
00066  *                                                                    *
00067  * It is a principal objective of the IUCr to promote the use of      *
00068  * CIF for the exchange and storage of scientific data. The IUCr's    *
00069  * sponsorship of the CIF development was motivated by its            *
00070  * responsibility to its scientific journals, which set the           *
00071  * standards in crystallographic publishing. The IUCr intends that    *
00072  * CIFs will be used increasingly for electronic submission of        *
00073  * manuscripts to these journals in future. The IUCr recognises       *
00074  * that, if the CIF and the STAR File are to be adopted as a means    *
00075  * for universal data exchange, the syntax of these files must be     *
00076  * strictly and uniformly adhered to. Even small deviations from      *
00077  * the syntax would ultimately cause the demise of the universal      *
00078  * file concept. Through its Copyrights and Patents the IUCr has      *
00079  * taken the steps needed to ensure strict conformance with this      *
00080  * syntax.                                                            *
00081  *                                                                    *
00082  * The IUCr policy on the use of the CIF and STAR File processes is   *
00083  * as follows:                                                        *
00084  * _________________________________________________________________  *
00085  *                                                                    *
00086  *  * 1 CIFs and STAR Files may be generated, stored or transmitted,  *
00087  *    without permission or charge, provided their purpose is not     *
00088  *    specifically for profit or commercial gain, and provided that   *
00089  *    the published syntax is strictly adhered to.                    *
00090  *  * 2 Computer software may be developed for use with CIFs or STAR  *
00091  *    files, without permission or charge, provided it is distributed *
00092  *    in the public domain. This condition also applies to software   *
00093  *    for which a charge is made, provided that its primary function  *
00094  *    is for use with files that satisfy condition 1 and that it is   *
00095  *    distributed as a minor component of a larger package of         *
00096  *    software.                                                       *
00097  *  * 3 Permission will be granted for the use of CIFs and STAR Files *
00098  *    for specific commercial purposes (such as databases or network  *
00099  *    exchange processes), and for the distribution of commercial     *
00100  *    CIF/STAR software, on written application to the IUCr Executive *
00101  *    Secretary, 2 Abbey Square, Chester CH1 2HU, England. The        *
00102  *    nature, terms and duration of the licences granted will be      *
00103  *    determined by the IUCr Executive and Finance Committees.        *
00104  *                                                                    *
00105  * _________________________________________________________________  *
00106  *                                                                    *
00107  * In summary, the IUCr wishes to promote the use of the STAR File    *
00108  * concepts as a standard universal data file. It will insist on      *
00109  * strict compliance with the published syntax for all                *
00110  * applications. To assist with this compliance, the IUCr provides    *
00111  * public domain software for checking the logical integrity of a     *
00112  * CIF, and for validating the data name definitions contained        *
00113  * within a CIF. Detailed information on this software, and the       *
00114  * associated dictionaries, may be obtained from the IUCr Office at   *
00115  * 5 Abbey Square, Chester CH1 2HU, England.                          *
00116  **********************************************************************/
00117 
00118 #ifdef __cplusplus
00119 
00120 extern "C" {
00121 
00122 #endif
00123 
00124 #include "cbf.h"
00125 #include "cbf_ascii.h"
00126 #include "cbf_binary.h"
00127 #include "cbf_compress.h"
00128 #include "cbf_file.h"
00129 #include "cbf_tree.h"
00130 #include "cbf_write.h"
00131 #include "cbf_write_binary.h"
00132 #include "cbf_read_mime.h"
00133 
00134 #include <stdlib.h>
00135 #include <string.h>
00136 #include <ctype.h>
00137 #include <limits.h>
00138 
00139 
00140   /* Check the value type */
00141 
00142 int cbf_value_type (char *value)
00143 {
00144   int test [6], C, count;
00145 
00146 
00147     /* Is the value missing? */
00148 
00149   if (!value)
00150 
00151     return 0;
00152 
00153 
00154     /* Is the value valid? */
00155 
00156   if ((*value & '\200') != '\200')
00157 
00158     return CBF_ARGUMENT;
00159     
00160 
00161     /* Has the value already been checked? */
00162 
00163   if ((value [0] & '\300') == '\300')
00164 
00165     return 0;
00166     
00167 
00168     /* Properties */
00169 
00170   memset (test, 0, sizeof (test));
00171 
00172   for (count = 1; value [count]; count++)
00173   {
00174     C = toupper (value [count]);
00175 
00176     test [0] |= isspace (C);
00177 
00178     test [1] |= C == '\n';
00179     test [2] |= C == '\'';
00180     test [3] |= C == '"';
00181 
00182     if (count <= 5)
00183     {
00184       test [4] |= C != " DATA_" [count];
00185       test [5] |= C != " LOOP_" [count];
00186 
00187       if (count <= 1)
00188 
00189         test [0] |= C == '_' || C == '\'' || C == '"' || C == '#';
00190     }
00191   }
00192 
00193   test [0] |= strcmp (&value [1], "?") == 0;
00194   test [0] |= strcmp (&value [1], ".") == 0;
00195 
00196 
00197     /* Simple word? */
00198 
00199   if (!test [0] && test [4] && test [5])
00200 
00201     *value = CBF_TOKEN_WORD;
00202 
00203   else
00204 
00205       /* Single line? */
00206 
00207     if (!test [1] && (!test [2] || !test [3]))
00208     {
00209       if (!test [2])
00210 
00211         *value = CBF_TOKEN_SQSTRING;
00212 
00213       else
00214 
00215         *value = CBF_TOKEN_DQSTRING;
00216     }
00217     else
00218 
00219         /* Multiple lines */    
00220 
00221       *value = CBF_TOKEN_SCSTRING;
00222 
00223 
00224     /* Success */
00225 
00226   return 0;
00227 }
00228 
00229 
00230   /* Write a datablock name to a file */
00231 
00232 int cbf_write_datablockname (const cbf_node *datablock, cbf_file *file)
00233 {
00234     /* Does the node exist? */
00235 
00236   if (!datablock)
00237 
00238     return CBF_ARGUMENT;
00239 
00240 
00241     /* Write the name */
00242 
00243   if (datablock->name)
00244   {
00245     cbf_failnez (cbf_write_string (file, "\ndata_"))
00246 
00247     cbf_failnez (cbf_write_string (file, datablock->name))
00248 
00249     cbf_failnez (cbf_write_character (file, '\n'))
00250   }
00251   else
00252 
00253     if (datablock->children)
00254 
00255       cbf_failnez (cbf_write_string (file, "\ndata_\n"))
00256 
00257 
00258     /* Success */
00259 
00260   return 0;
00261 }
00262 
00263 
00264   /* Write an item name to a file */
00265 
00266 int cbf_write_itemname (const cbf_node *column, cbf_file *file)
00267 {
00268   cbf_node *category;
00269 
00270 
00271     /* Get the category */
00272       
00273   cbf_failnez (cbf_find_parent (&category, column, CBF_CATEGORY))
00274 
00275 
00276     /* Check that the name is valid */
00277 
00278   if (!category->name && !column->name)
00279 
00280     return CBF_ARGUMENT;
00281 
00282 
00283     /* Write the category name */
00284 
00285   cbf_failnez (cbf_write_character (file, '_'))
00286 
00287   if (category->name)
00288   {
00289     cbf_failnez (cbf_write_string (file, category->name))
00290 
00291     cbf_failnez (cbf_write_character (file, '.'))
00292   }
00293 
00294 
00295     /* Write the column name */
00296 
00297   if (column->name)
00298 
00299     cbf_failnez (cbf_write_string (file, column->name))
00300 
00301 
00302     /* Success */
00303 
00304   return 0;
00305 }
00306 
00307 
00308   /* Write a value to a file */
00309 
00310 int cbf_write_value (cbf_node *column, unsigned int row, 
00311                      cbf_file *file, int isbuffer)
00312 {
00313   const char *text;
00314 
00315 
00316     /* Check the arguments */
00317 
00318   if (!column)
00319 
00320     return CBF_ARGUMENT;
00321 
00322   if (row >= column->children)
00323 
00324     return CBF_NOTFOUND;
00325 
00326 
00327     /* Get the value */
00328 
00329   cbf_failnez (cbf_get_columnrow (&text, column, row))
00330 
00331 
00332     /* Missing value? */
00333     
00334   if (!text)
00335 
00336     return cbf_write_ascii (text, file);
00337 
00338 
00339     /* Plain ASCII? */
00340 
00341   cbf_failnez (cbf_value_type ((char *) text))
00342 
00343   if (*text == CBF_TOKEN_WORD     ||
00344       *text == CBF_TOKEN_SQSTRING ||
00345       *text == CBF_TOKEN_DQSTRING ||
00346       *text == CBF_TOKEN_SCSTRING ||
00347       *text == CBF_TOKEN_NULL)
00348 
00349     return cbf_write_ascii (text, file);
00350 
00351 
00352     /* Plain binary? */
00353 
00354   if (*text == CBF_TOKEN_BIN || *text == CBF_TOKEN_TMP_BIN)
00355 
00356     return cbf_write_binary (column, row, file, isbuffer);
00357 
00358 
00359     /* Undecoded MIME? */
00360   
00361   if (*text == CBF_TOKEN_MIME_BIN)
00362   {
00363       /* Convert the value to a normal binary section */
00364       
00365     cbf_failnez (cbf_mime_temp (column, row))
00366   
00367     return cbf_write_binary (column, row, file, isbuffer);
00368   }
00369 
00370 
00371     /* Fail */
00372 
00373   return CBF_ARGUMENT;
00374 }
00375 
00376 
00377   /* Write a category to a file */
00378 
00379 int cbf_write_category (const cbf_node *category, cbf_file *file, int isbuffer)
00380 {
00381   unsigned int count, first, last, column, columns, row;
00382   
00383   int loop;
00384 
00385 
00386     /* Check the arguments */
00387 
00388   if (!category)
00389 
00390     return CBF_ARGUMENT;
00391 
00392     
00393     /* Print out columns of the same length in loops */
00394 
00395   for (first = 0, loop = 1; first < category->children; first = last)
00396   {
00397     columns = 1;
00398     
00399     if (category->child [first])
00400     {
00401       for (last = first + 1; last < category->children; last++)
00402 
00403         if (category->child [last])
00404         {
00405           if (category->child [last]->children != 
00406             category->child [first]->children)
00407 
00408             break;
00409             
00410           columns++;
00411         }
00412 
00413 
00414         /* Make a loop? */
00415 
00416       if (columns > 1 || category->child [first]->children > 1)
00417       {
00418         cbf_failnez (cbf_write_string (file, "\nloop_\n"))
00419 
00420         loop = 1;
00421       }
00422       else
00423       {
00424         if (loop)
00425 
00426           cbf_failnez (cbf_write_character (file, '\n'))
00427 
00428         loop = 0;
00429       }
00430 
00431 
00432         /* Write the items */
00433 
00434       for (count = first; count < last; count++)
00435       {
00436         cbf_failnez (cbf_write_itemname (category->child [count], file))
00437           
00438         if (loop)
00439 
00440           cbf_failnez (cbf_write_character (file, '\n'))
00441       }
00442 
00443 
00444         /* Write the values */
00445 
00446       for (row = 0; row < category->child [first]->children; row++)
00447       {
00448         for (column = first; column < last; column++)
00449 
00450           cbf_failnez (cbf_write_value (category->child [column], row, 
00451                                                        file, isbuffer))
00452 
00453         cbf_failnez (cbf_get_filecoordinates (file, NULL, &column))
00454 
00455         if (column)
00456 
00457           cbf_failnez (cbf_write_character (file, '\n'))
00458       }
00459     }
00460   }
00461 
00462 
00463     /* Success */
00464 
00465   return 0;
00466 }
00467 
00468 
00469   /* Write a node to a file */
00470 
00471 int cbf_write_node (const cbf_node *node, cbf_file *file, int isbuffer)
00472 {
00473   unsigned int count;
00474   
00475 
00476     /* Follow any links */
00477 
00478   node = cbf_get_link (node);
00479 
00480 
00481     /* Does the node exist? */
00482 
00483   if (!node)
00484 
00485     return CBF_ARGUMENT;
00486 
00487 
00488     /* Node type */
00489 
00490   switch (node->type)
00491   {
00492     case CBF_ROOT:
00493 
00494       cbf_failnez (cbf_write_string (file, "###CBF: VERSION 0.6\n"))
00495     
00496       if (file->write_encoding & ENC_NONE)
00497 
00498         cbf_failnez (cbf_write_string (file, 
00499                              "# CBF file written by cbflib v0.6\n"))
00500       else
00501 
00502         cbf_failnez (cbf_write_string (file, 
00503                              "# CIF file written by cbflib v0.6\n"))
00504 
00505       break;
00506 
00507     case CBF_DATABLOCK:
00508 
00509       cbf_failnez (cbf_write_datablockname (node, file))
00510 
00511       break;
00512 
00513     case CBF_CATEGORY:
00514 
00515       cbf_failnez (cbf_write_category (node, file, isbuffer))
00516 
00517       break;
00518 
00519     default:
00520 
00521       return CBF_ARGUMENT;
00522   }
00523 
00524 
00525     /* Write the children */
00526 
00527   if (node->type == CBF_ROOT || node->type == CBF_DATABLOCK)
00528 
00529     for (count = 0; count < node->children; count++)
00530 
00531       cbf_failnez (cbf_write_node (node->child [count], file, isbuffer))
00532 
00533 
00534     /* Flush the buffers */
00535 
00536   return cbf_flush_characters (file);
00537 }
00538 
00539 
00540 #ifdef __cplusplus
00541 
00542 }
00543 
00544 #endif