Back to index

python-biopython  1.60
cnexus.c
Go to the documentation of this file.
00001 /* Copyright 2005 by Frank Kauff.  All rights reserved.
00002  * This code is part of the Biopython distribution and governed by its
00003  * license. Please see the LICENSE file that should have been included
00004  * as part of this package.
00005  *
00006  * cnexus.c
00007  *
00008  * Parse input strings, cut out (nested) comments, deal with quoted text.
00009  * Input lines terminated with ; are separated by ASCII code 7 (something
00010  * that naturally doesn't occur in plain NEXUS files).
00011  *
00012  * Used by Nexus.py
00013  */
00014 
00015 #include <Python.h>
00016 #include <string.h>
00017 
00018 static PyObject * cnexus_scanfile(PyObject *self, PyObject *args)
00019 {
00020     PyObject *cleaninput;
00021     const char *input;
00022     char *scanned, *scanned_start;
00023     char t, quotelevel;
00024     int speciallevel, commlevel;
00025 
00026     quotelevel=0;
00027     speciallevel=0;
00028     commlevel=0;
00029     
00030     if (!PyArg_ParseTuple(args, "s", &input))
00031         return NULL;
00032     if (!(scanned=malloc(strlen(input)+1)))
00033         PyErr_NoMemory();
00034     scanned_start=scanned;
00035     for(t=*input;(t=*input);input++) 
00036     {
00037         /* end of standard quote */
00038         if (!(commlevel || speciallevel) && t==quotelevel)
00039             quotelevel=0;
00040         /* start of standard quote */
00041         else if (!quotelevel && !(commlevel || speciallevel) && (t=='\'' || t=='"'))
00042             quotelevel=t;
00043         /* start of comment outside quote */
00044         else if (!quotelevel  && t=='[')
00045         {
00046             /* check for special comments */
00047             /*if ((*(input+1)=='!' || *(input+1)=='&' || *(input+1)=='%' || 
00048                     *(input+1)=='/' || *(input+1)=='\\' || *(input+1)=='@')
00049                     && !(commlevel || speciallevel))
00050                 speciallevel=1;
00051             */
00052             if ((*(input+1)=='&') && !(commlevel || speciallevel))
00053                 speciallevel=1;
00054             else /* standard comment */
00055                 commlevel++;
00056         }
00057         else if (!quotelevel && t==']')
00058         {
00059             /* does it end a special comment? */
00060             if (speciallevel)
00061                 speciallevel=0;
00062             else
00063             {
00064                 commlevel--;
00065                 if (commlevel<0) /* error: unmatched ] */
00066                 {
00067                     free(scanned_start);
00068                     return Py_BuildValue("s","]");
00069                 }
00070                 continue;
00071             }
00072         }
00073         if (!commlevel)
00074         {
00075             /* we replace the ; at the end of command lines with special
00076              * character to make subsequent parsing of blocks easier */
00077             if (t==';' && !(quotelevel || speciallevel))
00078                 /* need an ascii code thats not part of a nexus file, used as
00079                  * separator */
00080                 *(scanned++)=7;
00081             else
00082                 *(scanned++)=t;
00083         }
00084         /* printf("t %c, commlevel %d, speciallevel %d, quotelevel '%c', scanned %d\n",
00085          * t,commlevel,speciallevel,quotelevel,scanned);
00086          */
00087     }               
00088     
00089     if (commlevel>0)
00090     {
00091         /* error: unmatched [ */
00092         free(scanned_start);
00093         return Py_BuildValue("s","[");
00094     }
00095     else
00096     {
00097         *scanned=0; /* end of string */
00098         cleaninput= Py_BuildValue("s",scanned_start);
00099         free(scanned_start);
00100         return cleaninput;
00101     }
00102 }
00103 
00104 static PyMethodDef cNexusMethods[]=
00105 {
00106     {"scanfile",cnexus_scanfile,METH_VARARGS,"Scan file and deal with comments and quotes."},
00107     {NULL,NULL,0,NULL}
00108 };
00109 
00110 #if PY_MAJOR_VERSION >= 3
00111 
00112 static struct PyModuleDef moduledef = {
00113         PyModuleDef_HEAD_INIT,
00114         "cnexus",
00115         NULL,
00116         -1,
00117         cNexusMethods,
00118         NULL,
00119         NULL,
00120         NULL,
00121         NULL
00122 };
00123 
00124 PyObject *
00125 PyInit_cnexus(void)
00126 {
00127     return PyModule_Create(&moduledef);
00128 }
00129 
00130 
00131 #else
00132 
00133 PyMODINIT_FUNC initcnexus(void)
00134 {
00135     (void) Py_InitModule("cnexus",cNexusMethods);
00136 }
00137 #endif