00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 #include <io.h>
00047 #include <fcntl.h>
00048 #include <sys/stat.h>
00049 #include <string.h>
00050 #include <stdarg.h>
00051 #include <time.h>
00052 #include <errno.h>
00053 #include <sys/nutdebug.h>
00054 #include <sys/event.h>
00055 
00056 #include <gorp/perci.h>
00057 
00062 
00063 
00064 
00071 void PerCiDump(FILE *stream, char *path)
00072 {
00073 #ifdef NUTDEBUG
00074     int fd;
00075     int got;
00076     perci_fast_reclen_t i;
00077     perci_fast_reclen_t ll;
00078     perci_recnum_t recnum;
00079     perci_reclen_t reclen;
00080     uint8_t *recbuf;
00081 
00082     fd = _open(path, _O_RDWR | _O_BINARY);
00083     if (fd == -1) {
00084         fprintf(stream, "Error %d opening %s\n", errno, path);
00085         return;
00086     } else {
00087         fprintf(stream, "Dump %ld bytes in %s\n", _filelength(fd), path);
00088         recbuf = malloc(PERCI_DATASIZE);
00089         for (recnum = 0;; recnum++) {
00090             got = _read(fd, &reclen, sizeof(perci_reclen_t));
00091             if (got <= 0) {
00092                 break;
00093             }
00094             fprintf(stream, "%03u %03u ", recnum, (unsigned int)reclen);
00095             got = _read(fd, recbuf, PERCI_DATASIZE);
00096             for (i = 0, ll = 0; i < (perci_fast_reclen_t) got && i <= (perci_fast_reclen_t) reclen; i++) {
00097                 if (recbuf[i] < ' ') {
00098                     ll += 2;
00099                     if (recbuf[i] == '\n') {
00100                         fputs("\\n", stream);
00101                     }
00102                     else if (recbuf[i] == '\r') {
00103                         fputs("\\r", stream);
00104                     }
00105                     else if (recbuf[i] == '\t') {
00106                         fputs("\\t", stream);
00107                     } else {
00108                         fprintf(stream, "\\x%02x", recbuf[i]);
00109                         ll += 2;
00110                     }
00111                 } else {
00112                     fputc(recbuf[i], stream);
00113                     ll++;
00114                 }
00115                 if (ll > 80) {
00116                     fprintf(stream, "...");
00117                     break;
00118                 }
00119             }
00120             fputc('\n', stream);
00121         }
00122         _close(fd);
00123         free(recbuf);
00124     }
00125 #endif
00126 }
00127 
00151 int PerCiInit(char *path, int recs)
00152 {
00153     int fd;
00154     int i;
00155     PERCI_RECORD *rec;
00156 
00157     
00158     NUTASSERT(path != NULL);
00159     NUTASSERT(recs >= 2);
00160 
00161     fd = _open(path, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY);
00162     if (fd == -1) {
00163         return -1;
00164     }
00165     rec = calloc(PERCI_RECSIZE, 1);
00166     if (rec) {
00167         for (i = 0; i < recs; i++) {
00168             _write(fd, rec, PERCI_RECSIZE);
00169         }
00170         _write(fd, rec, sizeof(perci_reclen_t));
00171         free(rec);
00172     }
00173     _close(fd);
00174 
00175     return 0;
00176 }
00177 
00202 PERCI_WRITER *PerCiOpen(char *path)
00203 {
00204     uint_fast8_t ok = 0;
00205     PERCI_WRITER *writer;
00206     perci_reclen_t reclen;
00207 
00208     
00209     NUTASSERT(path != NULL);
00210 
00211     
00212     writer = calloc(1, sizeof(PERCI_WRITER));
00213     if (writer) {
00214         
00215 
00216         writer->pcw_fd = _open(path, _O_RDWR | _O_BINARY);
00217         if (writer->pcw_fd != -1) {
00218             
00219 
00220             writer->pcw_size = _filelength(writer->pcw_fd);
00221             if (writer->pcw_size >= 2 * PERCI_RECSIZE + sizeof(perci_reclen_t)) {
00222                 writer->pcw_size -= sizeof(perci_reclen_t);
00223 
00224                 
00225 
00226 
00227                 _seek(writer->pcw_fd, 0, SEEK_SET);
00228                 for (writer->pcw_recnum = 0; writer->pcw_recnum < PERCI_MAX_RECORDS; writer->pcw_recnum++) {
00229                     
00230                     if (_read(writer->pcw_fd, &reclen, sizeof(perci_reclen_t)) != sizeof(perci_reclen_t)) {
00231                         
00232                         break;
00233                     }
00234                     
00235 
00236                     if (reclen < PERCI_DATASIZE) {
00237                         
00238                         writer->pcw_rec.pcd_len = reclen;
00239                         if (reclen && _read(writer->pcw_fd, writer->pcw_rec.pcd_data, reclen) != reclen) {
00240                             break;
00241                         }
00242                         NutEventPost(&writer->pcw_mutex);
00243                         ok = 1;
00244                         break;
00245                     }
00246                     
00247                     _seek(writer->pcw_fd, PERCI_DATASIZE, SEEK_CUR);
00248                 }
00249             }
00250         }
00251     }
00252     
00253     if (!ok && writer) {
00254         if (writer->pcw_fd != -1) {
00255             _close(writer->pcw_fd);
00256         }
00257         free(writer);
00258         writer = NULL;
00259     }
00260     return writer;
00261 }
00262 
00269 void PerCiFlush(PERCI_WRITER * writer)
00270 {
00271     
00272     NUTASSERT(writer != NULL);
00273     NUTASSERT(writer->pcw_fd != -1);
00274 
00275     _seek(writer->pcw_fd, writer->pcw_recnum * PERCI_RECSIZE, SEEK_SET);
00276     _write(writer->pcw_fd, &writer->pcw_rec, sizeof(perci_reclen_t) + writer->pcw_rec.pcd_len);
00277 }
00278 
00285 void PerCiClose(PERCI_WRITER * writer)
00286 {
00287     
00288     NUTASSERT(writer != NULL);
00289 
00290     if (writer->pcw_rec.pcd_len) {
00291         PerCiFlush(writer);
00292     }
00293     _close(writer->pcw_fd);
00294     free(writer);
00295 }
00296 
00305 int PerCiWrite(PERCI_WRITER * writer, CONST char *data, int len)
00306 {
00307     perci_fast_reclen_t cnt = 0;
00308     perci_fast_reclen_t num;
00309     perci_fast_reclen_t reclen;
00310 
00311     
00312     NUTASSERT(writer != NULL);
00313     NUTASSERT(writer->pcw_fd != -1);
00314     NUTASSERT(writer->pcw_rec.pcd_len <= PERCI_DATASIZE);
00315 
00316     NutEventWait(&writer->pcw_mutex, NUT_WAIT_INFINITE);
00317     while ((perci_fast_reclen_t) len > cnt) {
00318         
00319         reclen = (perci_fast_reclen_t) writer->pcw_rec.pcd_len;
00320         num = (perci_fast_reclen_t) len - cnt;
00321         if (num > PERCI_DATASIZE - reclen) {
00322             num = PERCI_DATASIZE - reclen;
00323         }
00324         
00325         memcpy(&writer->pcw_rec.pcd_data[reclen], data, num);
00326         writer->pcw_rec.pcd_len += num;
00327         cnt += num;
00328         data += num;
00329 
00330         
00331 
00332 
00333 
00334 
00335         if (writer->pcw_rec.pcd_len == PERCI_DATASIZE) {
00336             _seek(writer->pcw_fd, writer->pcw_recnum * PERCI_RECSIZE, SEEK_SET);
00337             if (_write(writer->pcw_fd, &writer->pcw_rec, sizeof(PERCI_RECORD)) != sizeof(PERCI_RECORD)) {
00338                 NutEventPost(&writer->pcw_mutex);
00339                 return -1;
00340             }
00341             writer->pcw_rec.pcd_len = 0;
00342             writer->pcw_recnum++;
00343             
00344             if (writer->pcw_recnum * PERCI_RECSIZE >= writer->pcw_size) {
00345                 writer->pcw_recnum = 0;
00346                 _seek(writer->pcw_fd, 0, SEEK_SET);
00347                 if (_write(writer->pcw_fd, &writer->pcw_rec.pcd_len, sizeof(perci_reclen_t)) != sizeof(perci_reclen_t)) {
00348                     NutEventPost(&writer->pcw_mutex);
00349                     return -1;
00350                 }
00351             }
00352         }
00353     }
00354     NutEventPost(&writer->pcw_mutex);
00355     return cnt;
00356 }
00357 
00372 int PerCiWriteVarList(PERCI_WRITER * writer, CONST char *fmt, va_list ap)
00373 {
00374     int cnt;
00375     char *line;
00376 
00377     
00378     NUTASSERT(fmt != NULL);
00379 
00380     line = malloc(PERCI_DATASIZE);
00381     if (line) {
00382         
00383         cnt = vsprintf(line, fmt, ap);
00384         NUTASSERT(cnt < PERCI_DATASIZE);
00385         cnt = PerCiWrite(writer, line, strlen(line));
00386         free(line);
00387     } else {
00388         cnt = -1;
00389     }
00390     return cnt;
00391 }
00392 
00393 
00404 int PerCiWriteFormat(PERCI_WRITER * writer, CONST char *fmt, ...)
00405 {
00406     int rc;
00407     va_list ap;
00408 
00409     
00410     NUTASSERT(fmt != NULL);
00411 
00412     va_start(ap, fmt);
00413     rc = PerCiWriteVarList(writer, fmt, ap);
00414     va_end(ap);
00415 
00416     return rc;
00417 }
00418 
00431 static perci_fast_reclen_t FindNextData(PERCI_WRITER * writer, perci_fast_recnum_t * recnum)
00432 {
00433     perci_reclen_t reclen;
00434     long pos;
00435     int got;
00436 
00437     
00438     NUTASSERT(writer != NULL);
00439 
00440     NutEventWait(&writer->pcw_mutex, NUT_WAIT_INFINITE);
00441     pos = *recnum * PERCI_RECSIZE;
00442     for (;;) {
00443         
00444 
00445         if (pos >= writer->pcw_size) {
00446             pos = 0;
00447             *recnum = 0;
00448         }
00449         
00450 
00451         if (*recnum == writer->pcw_recnum) {
00452             reclen = writer->pcw_rec.pcd_len;
00453             break;
00454         }
00455         
00456 
00457         _seek(writer->pcw_fd, pos, SEEK_SET);
00458         got = _read(writer->pcw_fd, &reclen, sizeof(perci_reclen_t));
00459         if (got == sizeof(perci_reclen_t) && reclen) {
00460             break;
00461         }
00462         
00463 
00464         pos += PERCI_RECSIZE;
00465         (*recnum)++;
00466     }
00467     NutEventPost(&writer->pcw_mutex);
00468     return reclen;
00469 }
00470 
00490 PERCI_READER *PerCiAttachReader(PERCI_WRITER * writer)
00491 {
00492     PERCI_READER *reader;
00493 
00494     
00495     NUTASSERT(writer != NULL);
00496 
00497     reader = malloc(sizeof(PERCI_READER));
00498     reader->pcr_cil = writer;
00499     reader->pcr_recpos = 0;
00500     
00501 
00502     reader->pcr_recnum = writer->pcw_recnum + 1;
00503     reader->pcr_reclen = FindNextData(writer, &reader->pcr_recnum);
00504 
00505     return reader;
00506 }
00507 
00514 void PerCiDetachReader(PERCI_READER * reader)
00515 {
00516     
00517     NUTASSERT(reader != NULL);
00518     free(reader);
00519 }
00520 
00532 int PerCiRead(PERCI_READER * reader, char *data, int len)
00533 {
00534     int cnt = 0;
00535     perci_fast_reclen_t num;
00536     int got;
00537 
00538     
00539     NUTASSERT(reader != NULL);
00540 
00541     
00542 
00543 
00544     while (len > cnt) {
00545         
00546         num = len - cnt;
00547         if (num > reader->pcr_reclen - reader->pcr_recpos) {
00548             num = reader->pcr_reclen - reader->pcr_recpos;
00549         }
00550         
00551 
00552         if (reader->pcr_recnum == reader->pcr_cil->pcw_recnum) {
00553             if (num) {
00554                 
00555                 memcpy(data, &reader->pcr_cil->pcw_rec.pcd_data[reader->pcr_recpos], num);
00556                 data += num;
00557                 cnt += num;
00558                 reader->pcr_recpos += num;
00559             } else {
00560                 
00561                 break;
00562             }
00563         }
00564         
00565         else {
00566             
00567             if (num) {
00568                 got = _read(reader->pcr_cil->pcw_fd, data, num);
00569                 if (got != num) {
00570                     break;
00571                 }
00572                 data += num;
00573                 cnt += num;
00574                 reader->pcr_recpos += num;
00575             } else {
00576                 
00577                 reader->pcr_recnum++;
00578                 reader->pcr_recpos = 0;
00579                 
00580                 reader->pcr_reclen = FindNextData(reader->pcr_cil, &reader->pcr_recnum);
00581                 if (reader->pcr_reclen == 0) {
00582                     
00583                     break;
00584                 }
00585             }
00586         }
00587     }
00588     return cnt;
00589 }
00590 
00602 int PerCiReadLine(PERCI_READER * reader, char *line, int len)
00603 {
00604     int cnt = 0;
00605     char *cp = line;
00606 
00607     
00608     NUTASSERT(reader != NULL);
00609     NUTASSERT(line != NULL);
00610 
00611     while (cnt < len) {
00612         if (PerCiRead(reader, cp, 1) != 1) {
00613             break;
00614         }
00615         cnt++;
00616         if (*cp++ == '\n') {
00617             break;
00618         }
00619     }
00620     *cp = 0;
00621 
00622     return cnt;
00623 }
00624