peakiso.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. /*
  2. * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
  3. * http://www.trevorwishart.co.uk
  4. * http://www.composersdesktop.com
  5. *
  6. This file is part of the CDP System.
  7. The CDP System is free software; you can redistribute it
  8. and/or modify it under the terms of the GNU Lesser General Public
  9. License as published by the Free Software Foundation; either
  10. version 2.1 of the License, or (at your option) any later version.
  11. The CDP System is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU Lesser General Public License for more details.
  15. You should have received a copy of the GNU Lesser General Public
  16. License along with the CDP System; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  18. 02111-1307 USA
  19. *
  20. */
  21. /*
  22. * Take a set of amp-frq data in the correct range,
  23. * find the notches in the spectrum.
  24. * Create a new spectrum by inverting these notches to become peaks
  25. */
  26. #define PSEUDOCENT (1.0009) // approx 1/64th of a tone
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <structures.h>
  30. #include <tkglobals.h>
  31. #include <pnames.h>
  32. #include <filetype.h>
  33. #include <processno.h>
  34. #include <modeno.h>
  35. #include <logic.h>
  36. #include <globcon.h>
  37. #include <cdpmain.h>
  38. #include <math.h>
  39. #include <mixxcon.h>
  40. #include <osbind.h>
  41. #include <science.h>
  42. #include <ctype.h>
  43. #include <sfsys.h>
  44. #include <string.h>
  45. #include <srates.h>
  46. int sloom = 0;
  47. int sloombatch = 0;
  48. const char* cdp_version = "6.1.0";
  49. //CDP LIB REPLACEMENTS
  50. //static int get_tk_cmdline_word(int *cmdlinecnt,char ***cmdline,char *q);
  51. static int handle_the_special_data(FILE *fpi, double **parray, int *itemcnt);
  52. static int test_the_special_data(double *parray, int itemcnt, double nyquist);
  53. static int peakiso(double *parray,int itemcnt,double *outarray,double minnotch);
  54. static int get_float_with_e_from_within_string(char **str,double *val);
  55. /**************************************** MAIN *********************************************/
  56. int main(int argc,char *argv[])
  57. {
  58. FILE *fpi, *fpo;
  59. int k;
  60. int exit_status;
  61. double *parray, *outarray;
  62. int itemcnt, srate;
  63. double minnotch = 0.0, nyquist;
  64. char temp[200], temp2[200];
  65. if(argc < 4 || argc > 5) {
  66. usage1();
  67. return(FAILED);
  68. }
  69. if(argc == 5) {
  70. if(sscanf(argv[4],"%lf",&minnotch) != 1) {
  71. fprintf(stderr,"CANNOT READ POINTCNT (%s)\n",argv[3]);
  72. return(FAILED);
  73. }
  74. if(minnotch > 1.0 || minnotch < 0.0) {
  75. fprintf(stderr,"INVALID MINIMUM NOTCH %s (range 0 - 1)\n",argv[3]);
  76. return(FAILED);
  77. }
  78. }
  79. if(sscanf(argv[3],"%d",&srate) != 1) {
  80. fprintf(stderr,"CANNOT READ SAMPLERATE (%s)\n",argv[3]);
  81. return(FAILED);
  82. }
  83. if(srate < 44100 || BAD_SR(srate)) {
  84. fprintf(stderr,"INVALID SAMPLE RATE ENTERED (44100,48000,88200,96000 only).\n");
  85. return(FAILED);
  86. }
  87. nyquist = (double)(srate/2);
  88. if((fpi = fopen(argv[1],"r")) == NULL) {
  89. fprintf(stderr,"CANNOT OPEN DATAFILE %s\n",argv[1]);
  90. return(FAILED);
  91. }
  92. if((exit_status = handle_the_special_data(fpi,&parray,&itemcnt))<0)
  93. return(FAILED);
  94. if((exit_status = test_the_special_data(parray,itemcnt,nyquist))<0)
  95. return(FAILED);
  96. if((outarray = (double *)malloc(itemcnt * sizeof(double)))==NULL) {
  97. fprintf(stderr,"INSUFFICIENT MEMORY for input data.\n");
  98. return(MEMORY_ERROR);
  99. }
  100. if((fpo = fopen(argv[2],"w")) == NULL) {
  101. fprintf(stderr,"CANNOT OPEN OUTPUT DATAFILE %s\n",argv[2]);
  102. return(FAILED);
  103. }
  104. if((exit_status = peakiso(parray,itemcnt,outarray,minnotch)) < 0)
  105. return(FAILED);
  106. k = 0;
  107. for(k = 0;k < itemcnt;k+=2) {
  108. sprintf(temp,"%lf",outarray[k]);
  109. sprintf(temp2,"%lf",outarray[k+1]);
  110. strcat(temp2,"\n");
  111. strcat(temp,"\t");
  112. strcat(temp,temp2);
  113. fputs(temp,fpo);
  114. }
  115. if(fclose(fpo)<0) {
  116. fprintf(stderr,"WARNING: Failed to close output data file %s.\n",argv[2]);
  117. }
  118. return(SUCCEEDED);
  119. }
  120. /******************************** USAGE1 ********************************/
  121. int usage1(void)
  122. {
  123. fprintf(stderr,
  124. "USAGE: peakiso datafile outdatafile srate [minnotch]\n"
  125. "\n"
  126. "Isolate peaks in a spectrum.\n"
  127. "\n"
  128. "DATAFILE textfile of frq/amp pairs.\n"
  129. "OUTDATAFILE isolated peaks as frq/amp pairs.\n"
  130. "MINNOTCH min depth of notch to qualify as peak-separator (Range 0-1).\n"
  131. "\n");
  132. return(USAGE_ONLY);
  133. }
  134. /************************** HANDLE_THE_SPECIAL_DATA **********************************/
  135. int handle_the_special_data(FILE *fpi, double **parray, int *itemcnt)
  136. {
  137. int cnt;
  138. double *p, dummy;
  139. char temp[200], *q;
  140. cnt = 0;
  141. p = &dummy;
  142. while(fgets(temp,200,fpi)==temp) {
  143. q = temp;
  144. if(*q == ';') // Allow comments in file
  145. continue;
  146. while(get_float_with_e_from_within_string(&q,p))
  147. cnt++;
  148. }
  149. if(ODD(cnt)) {
  150. fprintf(stderr,"Data not paired correctly in input data file\n");
  151. return(DATA_ERROR);
  152. }
  153. if(cnt == 0) {
  154. fprintf(stderr,"No data in input data file\n");
  155. return(DATA_ERROR);
  156. }
  157. if((*parray = (double *)malloc(cnt * sizeof(double)))==NULL) {
  158. fprintf(stderr,"INSUFFICIENT MEMORY for input data.\n");
  159. return(MEMORY_ERROR);
  160. }
  161. fseek(fpi,0,0);
  162. p = *parray;
  163. while(fgets(temp,200,fpi)==temp) {
  164. q = temp;
  165. if(*q == ';') // Allow comments in file
  166. continue;
  167. while(get_float_with_e_from_within_string(&q,p)) {
  168. p++;
  169. }
  170. }
  171. if(fclose(fpi)<0) {
  172. fprintf(stderr,"WARNING: Failed to close input data file.\n");
  173. }
  174. *itemcnt = cnt;
  175. return(FINISHED);
  176. }
  177. /************************** TEST_THE_SPECIAL_DATA **********************************/
  178. int test_the_special_data(double *parray, int itemcnt, double nyquist)
  179. {
  180. double *p;
  181. int isamp = 0, linecnt = 1;
  182. p = parray;
  183. while(linecnt <= itemcnt/2) {
  184. if(isamp) {
  185. if(*p < 0.0 || *p > 1.0) {
  186. fprintf(stderr,"Amp (%lf) out of range (0-1) at line %d in datafile.\n",*p,linecnt);
  187. return(DATA_ERROR);
  188. }
  189. } else {
  190. if(*p < 0.0 || *p > nyquist) {
  191. fprintf(stderr,"Frq (%lf) out of range (0 - %lf) at line %d in datafile.\n",*p,nyquist,linecnt);
  192. return(DATA_ERROR);
  193. }
  194. }
  195. if(!isamp)
  196. linecnt++;
  197. isamp = !isamp;
  198. p++;
  199. }
  200. return(FINISHED);
  201. }
  202. /************************** PEAKISO **********************************/
  203. int peakiso(double *parray,int itemcnt,double *outarray,double minnotch)
  204. {
  205. int ampat, trofampat, pkampbelowat, pkampaboveat, nexttrofat, writeat, j;
  206. double amp, lastamp, ampstep, lastampstep, belowstep, abovestep, notchdepth;
  207. double *pkbefore, *pkafter, *notch;
  208. int trofcnt, badnotches, jj, kk, notchwidth, prepeak, postpeak, pksttej, pkendej;
  209. int ampsttej, ampendej;
  210. double sttval, endval;
  211. int *pkbeforeat, *notchat, *orig_notchat;
  212. memset((char *)outarray,0,itemcnt * sizeof(double));
  213. /* FIND PEAKS AND TROUGHS */
  214. lastamp = parray[1];
  215. lastampstep = 0;
  216. ampat = 3;
  217. trofcnt = 0;
  218. while(ampat < itemcnt) {
  219. amp = parray[ampat];
  220. ampstep = amp - lastamp;
  221. if(ampstep < 0) {
  222. if(lastampstep > 0) { // falling after rise = peak
  223. outarray[ampat-2] = 1.0; // peak
  224. }
  225. lastampstep = ampstep;
  226. } else if(ampstep > 0) {
  227. if(lastampstep < 0) { // rising after fall = trough
  228. outarray[ampat-2] = -1.0; // trough
  229. trofcnt++;
  230. }
  231. lastampstep = ampstep;
  232. } // else, if flat : lastampstep not updated
  233. lastamp = amp; // saddle points are thus ignored, while flat peaks or troughs are spotted
  234. ampat += 2;
  235. }
  236. if(trofcnt == 0) {
  237. fprintf(stderr,"NO NOTCHES FOUND\n");
  238. for(j = 0; j < itemcnt; j+=2) {
  239. outarray[j] = parray[j];
  240. outarray[j+1] = 0.0;
  241. }
  242. return FINISHED;
  243. }
  244. if((pkbefore = (double *)malloc((trofcnt + 6) * sizeof(double)))==NULL) {
  245. fprintf(stderr,"INSUFFICIENT MEMORY for trough calculations (1).\n");
  246. return(MEMORY_ERROR);
  247. }
  248. if((pkafter = (double *)malloc((trofcnt + 6) * sizeof(double)))==NULL) {
  249. fprintf(stderr,"INSUFFICIENT MEMORY for trough calculations (2).\n");
  250. return(MEMORY_ERROR);
  251. }
  252. if((pkbeforeat = (int *)malloc((trofcnt + 6) * sizeof(int)))==NULL) {
  253. fprintf(stderr,"INSUFFICIENT MEMORY for trough calculations (1).\n");
  254. return(MEMORY_ERROR);
  255. }
  256. if((notch = (double *)malloc((trofcnt + 6) * sizeof(double)))==NULL) {
  257. fprintf(stderr,"INSUFFICIENT MEMORY for trough calculations (2).\n");
  258. return(MEMORY_ERROR);
  259. }
  260. if((notchat = (int *)malloc((trofcnt + 6) * sizeof(int)))==NULL) {
  261. fprintf(stderr,"INSUFFICIENT MEMORY for trough calculations (2).\n");
  262. return(MEMORY_ERROR);
  263. }
  264. if((orig_notchat = (int *)malloc((trofcnt + 6) * sizeof(int)))==NULL) {
  265. fprintf(stderr,"INSUFFICIENT MEMORY for trough calculations (2).\n");
  266. return(MEMORY_ERROR);
  267. }
  268. trofcnt = 0;
  269. ampat = 1;
  270. pkampbelowat = -1; // position of peak before trough
  271. pkampaboveat = -1; // position of peak after trough
  272. trofampat = -1; // position of trough
  273. /* NOTE LEVELS BEFORE AND AFTER NOTCHES AND MARK BAD NOTCHES */
  274. badnotches = 0;
  275. while(ampat < itemcnt) {
  276. amp = outarray[ampat];
  277. if(amp < 0.0) {
  278. if(pkampbelowat < 0) {
  279. pkampbelowat = 1;
  280. pkbefore[trofcnt] = parray[pkampbelowat];
  281. pkbeforeat[trofcnt] = pkampbelowat;
  282. }
  283. trofampat = ampat;
  284. notch[trofcnt] = parray[ampat];
  285. notchat[trofcnt] = ampat;
  286. } else if(amp > 0.0) { // found peak
  287. if(trofampat < 0) { // if not yet found trof, this is the peak below the trof
  288. pkampbelowat = ampat;
  289. pkbefore[trofcnt] = parray[pkampbelowat];
  290. pkbeforeat[trofcnt] = pkampbelowat;
  291. } else { // otherwise, its peak above trof : we now have complete notch
  292. pkampaboveat = ampat;
  293. pkafter[trofcnt] = parray[pkampaboveat];
  294. belowstep = pkbefore[trofcnt] - parray[trofampat];
  295. abovestep = pkafter[trofcnt] - parray[trofampat];
  296. notchdepth = min(belowstep,abovestep);
  297. if(notchdepth < minnotch)
  298. badnotches = 1;
  299. trofcnt++;
  300. pkampbelowat = pkampaboveat; // move to next notch
  301. pkbefore[trofcnt] = parray[pkampbelowat];
  302. pkbeforeat[trofcnt] = pkampbelowat;
  303. pkampaboveat = -1;
  304. trofampat = -1;
  305. }
  306. }
  307. ampat += 2; // if no peak found after last trough ..
  308. } // and last trof is not at very end (shoulf be impossible)
  309. if(trofampat >= 0 && (trofampat != itemcnt-1) && (pkampaboveat < 0)) {
  310. pkampaboveat = itemcnt - 1; // set peak to top edge of spectrum
  311. pkafter[trofcnt] = parray[pkampaboveat];
  312. belowstep = pkbefore[trofcnt] - parray[trofampat];
  313. abovestep = pkafter[trofcnt] - parray[trofampat];
  314. notchdepth = min(belowstep,abovestep);
  315. if(notchdepth < minnotch) // Mark notches that are not deep enough
  316. badnotches = 1;
  317. trofcnt++;
  318. pkbefore[trofcnt] = parray[pkampaboveat]; // Extra "pkbefore" after last notch
  319. pkbeforeat[trofcnt] = pkampaboveat;
  320. }
  321. for(kk=0;kk<trofcnt;kk++)
  322. orig_notchat[kk] = notchat[kk];
  323. /* ELIMINATE ADJACENT BAD NOTCHES */
  324. if(badnotches) {
  325. for(kk = 0;kk < trofcnt;kk++) { // x x
  326. if(pkbefore[kk] - notch[kk] < minnotch) { // x o x
  327. if((kk>0) && (pkbefore[kk] - notch[kk-1] < minnotch)) { // x x x x
  328. //ELIMINATE PEAK // x o
  329. outarray[pkbeforeat[kk]] = 0.0;
  330. // KEEP DEEPEST NOTCH
  331. if(notch[kk] <= notch[kk-1]) { // x x
  332. outarray[notchat[kk-1]] = 0.0; // x o x
  333. notch[kk-1] = notch[kk]; // x x x x
  334. notchat[kk-1]= notchat[kk]; // + o
  335. } else {
  336. outarray[notchat[kk]] = 0.0;
  337. }
  338. for(jj = kk+1;jj < trofcnt; jj++) {
  339. pkbefore[jj-1] = pkbefore[jj];
  340. pkbeforeat[jj-1] = pkbeforeat[jj];
  341. notch[jj-1] = notch[jj];
  342. notchat[jj-1] = notchat[jj];
  343. }
  344. pkbefore[jj-1] = pkbefore[jj];
  345. pkbeforeat[jj-1] = pkbeforeat[jj];
  346. } else if(pkbefore[kk+1] - notch[kk] < minnotch) { // o +
  347. //ELIMINATE NOTCH // x x x x
  348. outarray[notchat[kk]] = 0.0; // x o x
  349. //ELIMINATE LOWEST PEAK // x x
  350. if(pkbefore[kk] >= pkbefore[kk+1]) {
  351. outarray[pkbeforeat[kk+1]] = 0.0;
  352. if(kk < trofcnt-1) {
  353. notch[kk] = notch[kk+1];
  354. notchat[kk] = notchat[kk+1];
  355. }
  356. for(jj = kk+2;jj < trofcnt; jj++) {
  357. pkbefore[jj-1] = pkbefore[jj];
  358. pkbeforeat[jj-1] = pkbeforeat[jj];
  359. notch[jj-1] = notch[jj];
  360. notchat[jj-1] = notchat[jj];
  361. }
  362. pkbefore[jj-1] = pkbefore[jj];
  363. pkbeforeat[jj-1] = pkbeforeat[jj];
  364. } else {
  365. outarray[pkbeforeat[kk]] = 0.0;
  366. for(jj = kk+1;jj < trofcnt; jj++) {
  367. pkbefore[jj-1] = pkbefore[jj];
  368. pkbeforeat[jj-1] = pkbeforeat[jj];
  369. notch[jj-1] = notch[jj];
  370. notchat[jj-1] = notchat[jj];
  371. }
  372. pkbefore[jj-1] = pkbefore[jj];
  373. pkbeforeat[jj-1] = pkbeforeat[jj];
  374. }
  375. } else {
  376. //ELIMINATE PEAK BEFORE AND NOTCH // x
  377. outarray[pkbeforeat[kk]] = 0.0; // o x
  378. outarray[notchat[kk]] = 0.0; // x x x
  379. for(jj = kk+1;jj < trofcnt; jj++) { // x o
  380. pkbefore[jj-1] = pkbefore[jj]; // x
  381. pkbeforeat[jj-1] = pkbeforeat[jj];
  382. notch[jj-1] = notch[jj];
  383. notchat[jj-1] = notchat[jj];
  384. }
  385. pkbefore[jj-1] = pkbefore[jj];
  386. pkbeforeat[jj-1] = pkbeforeat[jj];
  387. }
  388. kk--;
  389. trofcnt--;
  390. } else if(pkbefore[kk+1] - notch[kk] < minnotch) { // x
  391. //ELIMINATE PEAK AFTER AND NOTCH // x o
  392. outarray[pkbeforeat[kk+1]] = 0.0; // x x x
  393. outarray[notchat[kk]] = 0.0; // o x
  394. if(kk < trofcnt-1) { // x
  395. notch[kk] = notch[kk+1];
  396. notchat[kk] = notchat[kk+1];
  397. }
  398. for(jj = kk+2;jj < trofcnt; jj++) {
  399. pkbefore[jj-1] = pkbefore[jj];
  400. pkbeforeat[jj-1] = pkbeforeat[jj];
  401. notch[jj-1] = notch[jj];
  402. notchat[jj-1] = notchat[jj];
  403. }
  404. pkbefore[jj-1] = pkbefore[jj];
  405. pkbeforeat[jj-1] = pkbeforeat[jj];
  406. kk--;
  407. trofcnt--;
  408. }
  409. }
  410. }
  411. writeat = 0; // position of write to output
  412. /* TRIM THE PEAKS */
  413. if(trofcnt > 0) {
  414. for(kk = 0;kk < trofcnt;kk++) {
  415. nexttrofat = notchat[kk] - 1; // nexttrofat points to the PAIR of values: notchat points to its amplitude
  416. if(kk == 0)
  417. prepeak = pkbeforeat[kk];
  418. else
  419. prepeak = pkbeforeat[kk] - notchat[kk-1];
  420. postpeak = notchat[kk] - pkbeforeat[kk];
  421. notchwidth = min(prepeak,postpeak);
  422. pksttej = (pkbeforeat[kk] - notchwidth) - 1;
  423. ampsttej = pksttej + 1;
  424. sttval = parray[ampsttej];
  425. ampsttej += 2;
  426. while(parray[ampsttej] < sttval) { // avoid any curling up again at peak edges
  427. sttval = parray[ampsttej] ;
  428. ampsttej += 2;
  429. }
  430. ampsttej -= 2;
  431. pksttej = ampsttej - 1;
  432. if(pksttej == pkendej) // Avoid peaks overlapping each other
  433. pksttej += 2;
  434. pkendej = (pkbeforeat[kk] + notchwidth) - 1;
  435. ampendej = pkendej + 1;
  436. endval = parray[ampendej];
  437. ampendej -= 2;
  438. while(parray[ampendej] < endval) { // avoid any curling up again at peak edges
  439. endval = parray[ampendej] ;
  440. ampendej -= 2;
  441. }
  442. ampendej += 2;
  443. pkendej = ampendej - 1;
  444. while(writeat < pksttej) {
  445. outarray[writeat] = parray[writeat];
  446. writeat++;
  447. outarray[writeat] = 0.0;
  448. writeat++;
  449. }
  450. while(writeat < pkendej) {
  451. outarray[writeat] = parray[writeat];
  452. writeat++;
  453. outarray[writeat] = parray[writeat];
  454. writeat++;
  455. }
  456. while(writeat < nexttrofat) {
  457. outarray[writeat] = parray[writeat];
  458. writeat++;
  459. outarray[writeat] = 0.0;
  460. writeat++;
  461. }
  462. }
  463. nexttrofat = itemcnt;
  464. prepeak = pkbeforeat[kk] - notchat[kk-1];
  465. postpeak = (itemcnt + 1) - pkbeforeat[kk];
  466. notchwidth = min(prepeak,postpeak);
  467. pksttej = (pkbeforeat[kk] - notchwidth) - 1;
  468. if(pksttej == pkendej)
  469. pksttej += 2;
  470. pkendej = (pkbeforeat[kk] + notchwidth) - 1;
  471. while(writeat <pksttej) {
  472. outarray[writeat] = parray[writeat];
  473. writeat++;
  474. outarray[writeat] = 0.0;
  475. writeat++;
  476. }
  477. while(writeat <pkendej) {
  478. outarray[writeat] = parray[writeat];
  479. writeat++;
  480. outarray[writeat] = parray[writeat];
  481. writeat++;
  482. }
  483. while(writeat < nexttrofat) {
  484. outarray[writeat] = parray[writeat];
  485. writeat++;
  486. outarray[writeat] = 0.0;
  487. writeat++;
  488. }
  489. } else {
  490. while(writeat < itemcnt) {
  491. outarray[writeat] = parray[writeat];
  492. writeat++;
  493. outarray[writeat] = 0.0;
  494. writeat++;
  495. }
  496. }
  497. return(FINISHED);
  498. }
  499. /************************** GET_FLOAT_WITH_E_FROM_WITHIN_STRING **************************
  500. * takes a pointer TO A POINTER to a string. If it succeeds in finding
  501. * a float it returns the float value (*val), and it's new position in the
  502. * string (*str).
  503. */
  504. int get_float_with_e_from_within_string(char **str,double *val)
  505. {
  506. char *p, *valstart;
  507. int decimal_point_cnt = 0, has_digits = 0, has_e = 0, lastchar = 0;
  508. p = *str;
  509. while(isspace(*p))
  510. p++;
  511. valstart = p;
  512. switch(*p) {
  513. case('-'): break;
  514. case('.'): decimal_point_cnt=1; break;
  515. default:
  516. if(!isdigit(*p))
  517. return(FALSE);
  518. has_digits = TRUE;
  519. break;
  520. }
  521. p++;
  522. while(!isspace(*p) && *p!=NEWLINE && *p!=ENDOFSTR) {
  523. if(isdigit(*p))
  524. has_digits = TRUE;
  525. else if(*p == 'e') {
  526. if(has_e || !has_digits)
  527. return(FALSE);
  528. has_e = 1;
  529. } else if(*p == '-') {
  530. if(!has_e || (lastchar != 'e'))
  531. return(FALSE);
  532. } else if(*p == '.') {
  533. if(has_e || (++decimal_point_cnt>1))
  534. return(FALSE);
  535. } else
  536. return(FALSE);
  537. lastchar = *p;
  538. p++;
  539. }
  540. if(!has_digits || sscanf(valstart,"%lf",val)!=1)
  541. return(FALSE);
  542. *str = p;
  543. return(TRUE);
  544. }