/*
DFT++ is a density functional package developed by the research group
of Professor Tomas Arias
Copyright 1996-2003 Sohrab Ismail-Beigi
This file is part of DFT++.
DFT++ is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
DFT++ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DFT++; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Please see the file CREDITS for a list of authors.
For academic users, we request that publications using results obtained with
this software reference
"New algebraic formulation of density functional calculation," by Sohrab Ismail-Beigi
and T.A. Arias, Computer Physics Communications 128:1-2, 1-45 (June 2000).
and, if using the wavelet basis, further reference
"Multiresolution analysis of electronic structure: semicardinal and wavelet bases,"
T.A. Arias, Reviews of Modern Physics 71:1, 267-311 (January 1999).
and
"Robust ab initio calculation of condensed matter: transparent convergence through
semicardinal multiresolution analysis,'' I.P. Daykov, T.A. Arias, and
Torkel D. Engeness, Physical Review Letters, 90:21, 216402 (May 2003).
For your convenience, preprints of the above articles may be obtained from
http://arXiv.org/abs/cond-mat/9909130, 9805262, and 0204411, respectively.
*/
/*
* Tairan Wang, November 18 1997
*
* Define our own version of IO functions.
*
* dft_text_FILE* dft_text_fopen(...); (done, wait for checking)
* int dft_text_fclose(dft_text_FILE*, ...); (done, wait for checking)
*
* dft_text_fgets(dft_text_FILE*, ...); (done, wait for checking)
* dft_text_fscanf(dft_text_FILE*, ...); (done, wait for checking)
* dft_text_rewind(dft_text_FILE*);
* dft_text_fputc_old(char c, dft_text_FILE *file);
*
*/
/* $Id: dft_text_FILE.cpp,v 1.7.2.2 2003/05/29 18:54:17 ivan Exp $ */
#include <stdarg.h>
#include <stdio.h>
#include "header.h"
#include "parallel.h"
// Member function definitions for class dft_text_FILE:
dft_text_FILE::dft_text_FILE()
{
my_id = System::Get_procID();
io_id = System::Get_IOprocID();
file_length = 0L;
file_string = current_pointer = old_pointer
= (char*) 0;
file_handle = (FILE*) 0;
}
dft_text_FILE::~dft_text_FILE()
{
if (file_string != NULL)
myfree(file_string);
if (file_handle != NULL)
fclose(file_handle);
}
void
dft_text_FILE::init()
{
current_pointer = old_pointer = file_string
= (char*) mymalloc(file_length,"file_string","dft_text_FILE");
}
///////////////////////////////////////////////////////
dft_text_FILE *
dft_text_fopen(const char *filename, const char *type)
{
dft_text_FILE *file;
// Need to consider what we do if type is not "r"
if (strncmp(type,"r",1)!=0)
die("dft_text_fopen don't know what to do with non-read opens.");
file = new dft_text_FILE;
#ifdef DFT_MPI
int flag;
if (file->my_id == file->io_id) {
// get the length of file
if ((file->file_handle = fopen(filename, "rb"))==NULL)
{ // open failed.
flag = 0;
// inform all other processors of failure.
MPI_Bcast(&flag, 1, MPI_INT, file->io_id, MPI_COMM_WORLD);
delete (file);
return ( (dft_text_FILE*) 0 );
}
flag = 1;
fseek(file->file_handle, 0L, SEEK_END); // move to the end
file->file_length = ftell(file->file_handle); // get the length
// inform all other processors of success.
MPI_Bcast(&flag, 1, MPI_INT, file->io_id, MPI_COMM_WORLD);
} else {
MPI_Bcast(&flag, 1, MPI_INT, file->io_id, MPI_COMM_WORLD);
if (flag == 0) { // open failure
delete (file);
return ( (dft_text_FILE*) 0 );
}
}
MPI_Bcast(&(file->file_length), 1, MPI_LONG, file->io_id, MPI_COMM_WORLD);
#else // DFT_MPI
// get the length of file
if ((file->file_handle = fopen(filename, "rb"))==NULL)
{ // open failed.
delete (file);
return ( (dft_text_FILE*) 0 );
}
fseek(file->file_handle, 0L, SEEK_END); // move to the end
file->file_length = ftell(file->file_handle); // get the length
#endif // DFT_MPI
if (file->file_length == 0) { // file has no content
delete(file);
return ( (dft_text_FILE*) 0 );
}
// allocate file_string;
file->init();
if (file->my_id == file->io_id) {
rewind(file->file_handle);
fread(file->file_string,file->file_length,1,file->file_handle);
}
#ifdef DFT_MPI
MPI_Bcast(file->file_string, file->file_length, MPI_CHAR, file->io_id, MPI_COMM_WORLD);
MPI_Barrier(MPI_COMM_WORLD);
#endif // DFT_MPI
return (file);
}
/*
* dft_text_FILE::expand_include()
*
* expand the includes to read all include files too.
* not circular include checks!!! Be careful.
*/
void
dft_text_FILE::expand_include()
{
if (my_id == io_id) {
// file_string is already pointed at a character string of the file.
int done = FALSE, n_includes = 0, i, found = FALSE;
FILE ** inc_file;
long int *inc_file_length, tot_length = file_length;
char file_name[DFT_FILENAME_LEN], **inc_file_ptr0, **inc_file_ptr1, *p;
char line[DFT_LINE_LEN], key[DFT_MSG_LEN];
while (! done) {
n_includes = 0;
// go and count all includes,
while (dft_text_fgets(line,DFT_LINE_LEN,'\\',this) != NULL) {
if (sscanf(line,"%s",key) > 0) {
if ( MATCH(key,"include") ) {
n_includes++;
}
}
}
dft_text_rewind(this);
if ( n_includes > 0 ) {
inc_file = (FILE**) mymalloc(sizeof(FILE*)*n_includes,
"inc_file",
"dft_text_FILE::expand_include");
inc_file_length = (long int*)mymalloc(sizeof(long int)*n_includes,
"inc_file_length",
"dft_text_FILE::expand_include");
inc_file_ptr0 = (char**) mymalloc(sizeof(char*)*n_includes,
"inc_file_ptr0",
"dft_text_FILE::expand_include");
inc_file_ptr1 = (char**) mymalloc(sizeof(char*)*n_includes,
"inc_file_ptr1",
"dft_text_FILE::expand_include");
for (i = 0; i < n_includes; i++) {
// find next include, get name to file_name, inc_file_ptr0/1[i] set.
found = FALSE;
while ( (!found ) && (dft_text_fgets(line,DFT_LINE_LEN,'\\',this) != NULL)) {
if (sscanf(line,"%s",key) > 0)
if ( MATCH(key,"include") )
if (sscanf(line,"%*s %s",file_name) > 0) {
inc_file_ptr0[i] = old_pointer;
inc_file_ptr1[i] = current_pointer;
found = TRUE;
}
}
if ( (inc_file[i] = fopen(file_name,"rb")) != NULL) {
fseek(inc_file[i], 0L, SEEK_END);
inc_file_length[i] = ftell(inc_file[i]);
tot_length += inc_file_length[i]
- (inc_file_ptr1[i] - inc_file_ptr0[i]);
rewind(inc_file[i]);
} else {
inc_file_length[i] = 0L;
}
}
dft_text_rewind(this);
// now has the tot_length;
long int section_length;
p = (char*) mymalloc(tot_length,"","");
file_string = p;
for (i = 0; i < n_includes; i++) {
section_length = inc_file_ptr0[i] - current_pointer;
strncpy(p, current_pointer, section_length);
p += section_length;
current_pointer = inc_file_ptr1[i];
if (inc_file_length[i] > 0L)
fread(p,inc_file_length[i],1,inc_file[i]);
p += inc_file_length[i];
fclose(inc_file[i]);
}
// now the last chunk:
strncpy(p,current_pointer, old_pointer+file_length-current_pointer-1);
// release temporary variables
myfree(inc_file);
myfree(inc_file_length);
myfree(inc_file_ptr0);
myfree(inc_file_ptr1);
// now can deallocate old string,
myfree(old_pointer);
dft_text_rewind(this);
file_length = tot_length;
} else {
done = TRUE;
}
}
}
#ifdef DFT_MPI
// now also need to tell all other processors to
// receive this new file string.
MPI_Bcast(&file_length, 1, MPI_LONG, io_id, MPI_COMM_WORLD);
if (file_length <= 0L) { // file has no content. How does this happen?
die("Fatal error in dft_text_FILE::expand_include, file length <=0\n");
}
if (my_id != io_id) {
if (file_string != NULL)
myfree(file_string);
init();
}
MPI_Bcast(file_string, file_length, MPI_CHAR, io_id, MPI_COMM_WORLD);
MPI_Barrier(MPI_COMM_WORLD);
#endif // DFT_MPI
}
int
dft_text_fclose(dft_text_FILE* file)
{
delete file;
return 0; // assume success.
}
/*
* dft_text_fgets() reads in at most one less than n characters from
* stream and stores them into the buffer pointed to by s.
* Reading stops after an EOF or a newline. If a newline is
* read, it is stored into the buffer. A '\0' is stored
* after the last character in the buffer.
*/
char *
dft_text_fgets(char * s, int n, dft_text_FILE * file)
{
int i;
file->old_pointer = file->current_pointer; // trickery to track the beginning.
if (file->current_pointer + n - 1 > file->file_string + file->file_length)
{
n = file->file_string + file->file_length - file->current_pointer + 1;
}
for (i = 0; i < n-1; i++)
{
s[i] = file->current_pointer[i];
if (file->current_pointer[i] == '\n')
{ // end of line
i ++;
break; // break the for loop, stop reading.
}
else if (file->current_pointer[i] == '\0')
{ // encounter string termination character
break; // break the for loop, stop reading.
}
}
if (i > 0) {
s[i] = '\0'; // put terminating character in s;
file->current_pointer += i; // increment pointer
return s; // upon success
} else {
return ( (char *) 0 ); // upon failure
}
}
/*
* This function reads in at most one less than n characters from
* stream and stores them into the buffer pointed to by s.
*
* Reading will continue across newlines if they are terminated with
* special character 'c', say '\'.
*
* Reading stops after an EOF or a newline. If a newline is
* read, it is stored into the buffer. A '\0' is stored
* after the last character in the buffer.
*/
char *
dft_text_fgets(char * s, int n, char c, dft_text_FILE * file)
{
int i, j, m = n;
file->old_pointer = file->current_pointer; // trickery to track the beginning.
if (file->current_pointer + m - 1 > file->file_string + file->file_length)
{
m = file->file_string + file->file_length - file->current_pointer + 1;
}
for (i = j = 0; i < m-1; i++, j++)
{
s[i] = file->current_pointer[j];
if (file->current_pointer[j] == '\n')
{
if ( (j == 0) || (file->current_pointer[j-1] != c) ) {
// end of line
i++; j++;
break; // break the for loop, stop reading.
} else {
// read line continuation marker
// back track i;
i -= 2;
}
}
else if (file->current_pointer[j] == '\0')
{ // encounter string termination character
break; // break the for loop, stop reading.
}
}
if (i == n-1) {
die(">>Within dft_text_FILE dft_text_fgets(). Line too long. Increase line length");
}
if (i > 0) {
s[i] = '\0'; // put terminating character in s;
file->current_pointer += j; // increment pointer
return s; // upon success
} else {
return ( (char *) 0 ); // upon failure
}
}
void
dft_text_rewind(dft_text_FILE * file)
{
file->current_pointer = file->old_pointer
= file->file_string;
}
// MODIFIES input stream!! USE WITH CAUTION!!
void
dft_text_fputc_old(char c, dft_text_FILE * file)
{
file->old_pointer[0] = c;
}
/*
Prof Arias's scanf, "pascanf". It should would just like dft_text_fscanf
except that the first argument is a pointer to the string holding the
input stream, rather than a file-pointer. (By string, I mean a
pointer to the first character of the string.) See below for an
example for the use of this program.
NOTE: the string is updated as the input is read so that the next
call will start reading at the appropriate place. This is
convenient, but it does mean that the FIRST ARGUMENT IS DESROYED by
the time you are done reading the file.
ERRORS generated here by sscanf are passed back as the value EOF
for the function call.
BUGS: The code should work, except for those special cases for
which it traps and complains about, before terminating execution.
Hopefully, the cases I haven't handled are rare. We could easily
take care of those cases if they start comming up a lot.
*/
int
dft_text_fscanf( dft_text_FILE *file, const char *fmtin, ...)
{
#define Lenmx 1024 /* Maximum allowable length for the format specifier */
/* Variable argument list pointer */
va_list ap;
/* Internal temporary variables */
char format[Lenmx]; /* Stores writable copy of input conversion specifier */
char fmt2[Lenmx]; /* Used to store input conversions one item at a time */
char *fmt,*fmt1; /* Pointers into format for parsing each specifier */
char c; /* Temp storage for characters we set to \0 in while parsing */
void *item; /* Used with va_arg to hold pointers poped off the stack */
int assigned_items = 0; /* Keep track of number of successful conversion made */
int used; /* Used with sscanf to determine length of input stream consumed */
int len; /* Counts up string length for safety */
char** stream;
file->old_pointer = file->current_pointer; // trickery to track the beginning.
stream = &(file->current_pointer);
/* Copy format string into local writable space (fomat), and check for length
and presence of unwated *'s (a smarter version could handle the *'s */
strncpy(format,fmtin,Lenmx);
for (len=0; len<Lenmx; len++)
if (format[len]=='\0') break;
format[Lenmx-1]='\0';
if (len+3>=Lenmx)
die("\n\nError: not enough space (Lenmx) in pascanf for input conversion string!\n(conversion string=\"%s\")\n\n",format);
fmt=format;
while (*fmt) /* Check for '*' characters and length */
if (*(fmt++)=='*')
die("\n\nError: pascanf does not treat '*' in input conversion strings!\n(conversion string=\"%s\")\n\n",format);
fmt=format;
/* printf("INPUT: %d character format: \"%s\"\n",len,fmt); */
/* Initialize variable argument list to proper point in the stack */
va_start(ap, fmtin);
/* This loop parses the format, picking out each %-field */
while (*fmt)
{
fmt1=fmt;
fmt++;
while (*fmt != '\0' && *fmt != '%') fmt++; /* Locate % or "EOF" */
/* We have now identified a single input field, prepare to use sscanf
to read it in. Note that to do this, we have to update the pointer
into the input stream. To do this we use the %n option on sscanf
and put the number of characters consumed from the stream into
the variable "used". */
if (*fmt=='%' && *fmt1=='%' && fmt==fmt1+1)
{ /* %% constitutes a special case where the input field contains
two %'s and which is the only field beginning with % which
doesn't consume a pointer from the stack. */
fmt++; /* Claim the second % as part of this input field */
strcpy(fmt2,"%% %n"); /* Build format string, note we need
the %n to get the amount of stream
consumed */
/* printf("Input stream: \"%s\" / Format: \"%s\"\n",(*stream),fmt2); */
/* Scan stream with error check */
if (sscanf((*stream),fmt2,&used)!=0) return(EOF);
}
else
{
/* Build into fmt2 format string for only the field from
[fmt,fmt1] including the %n which we need for acounting
consumption of the stream */
c=*fmt; *fmt='\0'; strcpy(fmt2,fmt1); *fmt=c;
strcat(fmt2,"%n");
/* printf("Input stream: \"%s\" / Format: \"%s\"\n",(*stream),fmt2); */
if (*fmt2=='%')
{ /* An actual input item! Consume one argument from stack!!! */
item=va_arg(ap, void *);
/* Scan stream with error check */
if (sscanf((*stream),fmt2,item,&used)!=1) return(EOF);
assigned_items ++;
}
else
{ /* Simple text advance through stream (no argument from stack) */
/* Scan stream with error check */
if (sscanf((*stream),fmt2,&used)!=0) return(EOF);
}
}
/* Advance stream pointer */
(*stream)+=used;
}
return assigned_items;
}
syntax highlighted by Code2HTML, v. 0.9.1