]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - Plugson/src/Core/ventoy_json.c
Update README.md
[Ventoy.git] / Plugson / src / Core / ventoy_json.c
1 /******************************************************************************
2 * ventoy_json.c
3 *
4 * Copyright (c) 2021, longpanda <admin@ventoy.net>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <errno.h>
27 #if defined(_MSC_VER) || defined(WIN32)
28 #else
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <linux/limits.h>
32 #endif
33 #include <ventoy_define.h>
34 #include <ventoy_util.h>
35 #include <ventoy_json.h>
36
37 static void vtoy_json_free(VTOY_JSON *pstJsonHead)
38 {
39 VTOY_JSON *pstNext = NULL;
40
41 while (NULL != pstJsonHead)
42 {
43 pstNext = pstJsonHead->pstNext;
44 if ((pstJsonHead->enDataType < JSON_TYPE_BUTT) && (NULL != pstJsonHead->pstChild))
45 {
46 vtoy_json_free(pstJsonHead->pstChild);
47 }
48
49 free(pstJsonHead);
50 pstJsonHead = pstNext;
51 }
52
53 return;
54 }
55
56 static char *vtoy_json_skip(const char *pcData)
57 {
58 while ((NULL != pcData) && ('\0' != *pcData) && (*pcData <= 32))
59 {
60 pcData++;
61 }
62
63 return (char *)pcData;
64 }
65
66 VTOY_JSON *vtoy_json_find_item
67 (
68 VTOY_JSON *pstJson,
69 JSON_TYPE enDataType,
70 const char *szKey
71 )
72 {
73 while (NULL != pstJson)
74 {
75 if ((enDataType == pstJson->enDataType) &&
76 (0 == strcmp(szKey, pstJson->pcName)))
77 {
78 return pstJson;
79 }
80 pstJson = pstJson->pstNext;
81 }
82
83 return NULL;
84 }
85
86 static int vtoy_json_parse_number
87 (
88 VTOY_JSON *pstJson,
89 const char *pcData,
90 const char **ppcEnd
91 )
92 {
93 unsigned long Value;
94
95 Value = strtoul(pcData, (char **)ppcEnd, 10);
96 if (*ppcEnd == pcData)
97 {
98 vdebug("Failed to parse json number %s.\n", pcData);
99 return JSON_FAILED;
100 }
101
102 pstJson->enDataType = JSON_TYPE_NUMBER;
103 pstJson->unData.lValue = Value;
104
105 return JSON_SUCCESS;
106 }
107
108 static int vtoy_json_parse_string
109 (
110 char *pcNewStart,
111 char *pcRawStart,
112 VTOY_JSON *pstJson,
113 const char *pcData,
114 const char **ppcEnd
115 )
116 {
117 uint32_t uiLen = 0;
118 const char *pcPos = NULL;
119 const char *pcTmp = pcData + 1;
120
121 *ppcEnd = pcData;
122
123 if ('\"' != *pcData)
124 {
125 return JSON_FAILED;
126 }
127
128 pcPos = strchr(pcTmp, '\"');
129 if ((NULL == pcPos) || (pcPos < pcTmp))
130 {
131 vdebug("Invalid string %s.\n", pcData);
132 return JSON_FAILED;
133 }
134
135 if (*(pcPos - 1) == '\\')
136 {
137 for (pcPos++; *pcPos; pcPos++)
138 {
139 if (*pcPos == '"' && *(pcPos - 1) != '\\')
140 {
141 break;
142 }
143 }
144
145 if (*pcPos == 0 || pcPos < pcTmp)
146 {
147 vdebug("Invalid quotes string %s.", pcData);
148 return JSON_FAILED;
149 }
150 }
151
152 *ppcEnd = pcPos + 1;
153 uiLen = (uint32_t)(unsigned long)(pcPos - pcTmp);
154
155 pstJson->enDataType = JSON_TYPE_STRING;
156 pstJson->unData.pcStrVal = pcNewStart + (pcTmp - pcRawStart);
157 pstJson->unData.pcStrVal[uiLen] = '\0';
158
159 return JSON_SUCCESS;
160 }
161
162 static int vtoy_json_parse_array
163 (
164 char *pcNewStart,
165 char *pcRawStart,
166 VTOY_JSON *pstJson,
167 const char *pcData,
168 const char **ppcEnd
169 )
170 {
171 int Ret = JSON_SUCCESS;
172 VTOY_JSON *pstJsonChild = NULL;
173 VTOY_JSON *pstJsonItem = NULL;
174 const char *pcTmp = pcData + 1;
175
176 *ppcEnd = pcData;
177 pstJson->enDataType = JSON_TYPE_ARRAY;
178
179 if ('[' != *pcData)
180 {
181 return JSON_FAILED;
182 }
183
184 pcTmp = vtoy_json_skip(pcTmp);
185
186 if (']' == *pcTmp)
187 {
188 *ppcEnd = pcTmp + 1;
189 return JSON_SUCCESS;
190 }
191
192 JSON_NEW_ITEM(pstJson->pstChild, JSON_FAILED);
193
194 Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJson->pstChild, pcTmp, ppcEnd);
195 if (JSON_SUCCESS != Ret)
196 {
197 vdebug("Failed to parse array child.\n");
198 return JSON_FAILED;
199 }
200
201 pstJsonChild = pstJson->pstChild;
202 pcTmp = vtoy_json_skip(*ppcEnd);
203 while ((NULL != pcTmp) && (',' == *pcTmp))
204 {
205 JSON_NEW_ITEM(pstJsonItem, JSON_FAILED);
206 pstJsonChild->pstNext = pstJsonItem;
207 pstJsonItem->pstPrev = pstJsonChild;
208 pstJsonChild = pstJsonItem;
209
210 Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd);
211 if (JSON_SUCCESS != Ret)
212 {
213 vdebug("Failed to parse array child.\n");
214 return JSON_FAILED;
215 }
216 pcTmp = vtoy_json_skip(*ppcEnd);
217 }
218
219 if ((NULL != pcTmp) && (']' == *pcTmp))
220 {
221 *ppcEnd = pcTmp + 1;
222 return JSON_SUCCESS;
223 }
224 else
225 {
226 *ppcEnd = pcTmp;
227 return JSON_FAILED;
228 }
229 }
230
231 static int vtoy_json_parse_object
232 (
233 char *pcNewStart,
234 char *pcRawStart,
235 VTOY_JSON *pstJson,
236 const char *pcData,
237 const char **ppcEnd
238 )
239 {
240 int Ret = JSON_SUCCESS;
241 VTOY_JSON *pstJsonChild = NULL;
242 VTOY_JSON *pstJsonItem = NULL;
243 const char *pcTmp = pcData + 1;
244
245 *ppcEnd = pcData;
246 pstJson->enDataType = JSON_TYPE_OBJECT;
247
248 if ('{' != *pcData)
249 {
250 return JSON_FAILED;
251 }
252
253 pcTmp = vtoy_json_skip(pcTmp);
254 if ('}' == *pcTmp)
255 {
256 *ppcEnd = pcTmp + 1;
257 return JSON_SUCCESS;
258 }
259
260 JSON_NEW_ITEM(pstJson->pstChild, JSON_FAILED);
261
262 Ret = vtoy_json_parse_string(pcNewStart, pcRawStart, pstJson->pstChild, pcTmp, ppcEnd);
263 if (JSON_SUCCESS != Ret)
264 {
265 vdebug("Failed to parse array child.\n");
266 return JSON_FAILED;
267 }
268
269 pstJsonChild = pstJson->pstChild;
270 pstJsonChild->pcName = pstJsonChild->unData.pcStrVal;
271 pstJsonChild->unData.pcStrVal = NULL;
272
273 pcTmp = vtoy_json_skip(*ppcEnd);
274 if ((NULL == pcTmp) || (':' != *pcTmp))
275 {
276 *ppcEnd = pcTmp;
277 return JSON_FAILED;
278 }
279
280 Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd);
281 if (JSON_SUCCESS != Ret)
282 {
283 vdebug("Failed to parse array child.\n");
284 return JSON_FAILED;
285 }
286
287 pcTmp = vtoy_json_skip(*ppcEnd);
288 while ((NULL != pcTmp) && (',' == *pcTmp))
289 {
290 JSON_NEW_ITEM(pstJsonItem, JSON_FAILED);
291 pstJsonChild->pstNext = pstJsonItem;
292 pstJsonItem->pstPrev = pstJsonChild;
293 pstJsonChild = pstJsonItem;
294
295 Ret = vtoy_json_parse_string(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd);
296 if (JSON_SUCCESS != Ret)
297 {
298 vdebug("Failed to parse array child.\n");
299 return JSON_FAILED;
300 }
301
302 pcTmp = vtoy_json_skip(*ppcEnd);
303 pstJsonChild->pcName = pstJsonChild->unData.pcStrVal;
304 pstJsonChild->unData.pcStrVal = NULL;
305 if ((NULL == pcTmp) || (':' != *pcTmp))
306 {
307 *ppcEnd = pcTmp;
308 return JSON_FAILED;
309 }
310
311 Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd);
312 if (JSON_SUCCESS != Ret)
313 {
314 vdebug("Failed to parse array child.\n");
315 return JSON_FAILED;
316 }
317
318 pcTmp = vtoy_json_skip(*ppcEnd);
319 }
320
321 if ((NULL != pcTmp) && ('}' == *pcTmp))
322 {
323 *ppcEnd = pcTmp + 1;
324 return JSON_SUCCESS;
325 }
326 else
327 {
328 *ppcEnd = pcTmp;
329 return JSON_FAILED;
330 }
331 }
332
333 int vtoy_json_parse_value
334 (
335 char *pcNewStart,
336 char *pcRawStart,
337 VTOY_JSON *pstJson,
338 const char *pcData,
339 const char **ppcEnd
340 )
341 {
342 pcData = vtoy_json_skip(pcData);
343
344 switch (*pcData)
345 {
346 case 'n':
347 {
348 if (0 == strncmp(pcData, "null", 4))
349 {
350 pstJson->enDataType = JSON_TYPE_NULL;
351 *ppcEnd = pcData + 4;
352 return JSON_SUCCESS;
353 }
354 break;
355 }
356 case 'f':
357 {
358 if (0 == strncmp(pcData, "false", 5))
359 {
360 pstJson->enDataType = JSON_TYPE_BOOL;
361 pstJson->unData.lValue = 0;
362 *ppcEnd = pcData + 5;
363 return JSON_SUCCESS;
364 }
365 break;
366 }
367 case 't':
368 {
369 if (0 == strncmp(pcData, "true", 4))
370 {
371 pstJson->enDataType = JSON_TYPE_BOOL;
372 pstJson->unData.lValue = 1;
373 *ppcEnd = pcData + 4;
374 return JSON_SUCCESS;
375 }
376 break;
377 }
378 case '\"':
379 {
380 return vtoy_json_parse_string(pcNewStart, pcRawStart, pstJson, pcData, ppcEnd);
381 }
382 case '[':
383 {
384 return vtoy_json_parse_array(pcNewStart, pcRawStart, pstJson, pcData, ppcEnd);
385 }
386 case '{':
387 {
388 return vtoy_json_parse_object(pcNewStart, pcRawStart, pstJson, pcData, ppcEnd);
389 }
390 case '-':
391 {
392 return vtoy_json_parse_number(pstJson, pcData, ppcEnd);
393 }
394 default :
395 {
396 if (*pcData >= '0' && *pcData <= '9')
397 {
398 return vtoy_json_parse_number(pstJson, pcData, ppcEnd);
399 }
400 }
401 }
402
403 *ppcEnd = pcData;
404 vdebug("Invalid json data %u.\n", (uint8_t)(*pcData));
405 return JSON_FAILED;
406 }
407
408 VTOY_JSON * vtoy_json_create(void)
409 {
410 VTOY_JSON *pstJson = NULL;
411
412 pstJson = (VTOY_JSON *)zalloc(sizeof(VTOY_JSON));
413 if (NULL == pstJson)
414 {
415 return NULL;
416 }
417
418 return pstJson;
419 }
420
421 int vtoy_json_parse(VTOY_JSON *pstJson, const char *szJsonData)
422 {
423 uint32_t uiMemSize = 0;
424 int Ret = JSON_SUCCESS;
425 char *pcNewBuf = NULL;
426 const char *pcEnd = NULL;
427
428 uiMemSize = strlen(szJsonData) + 1;
429 pcNewBuf = (char *)malloc(uiMemSize);
430 if (NULL == pcNewBuf)
431 {
432 vdebug("Failed to alloc new buf.\n");
433 return JSON_FAILED;
434 }
435 memcpy(pcNewBuf, szJsonData, uiMemSize);
436 pcNewBuf[uiMemSize - 1] = 0;
437
438 Ret = vtoy_json_parse_value(pcNewBuf, (char *)szJsonData, pstJson, szJsonData, &pcEnd);
439 if (JSON_SUCCESS != Ret)
440 {
441 vdebug("Failed to parse json data start=%p, end=%p.\n", szJsonData, pcEnd);
442 return JSON_FAILED;
443 }
444
445 return JSON_SUCCESS;
446 }
447
448 int vtoy_json_parse_ex(VTOY_JSON *pstJson, const char *szJsonData, int szLen)
449 {
450 uint32_t uiMemSize = 0;
451 int Ret = JSON_SUCCESS;
452 char *pcNewBuf = NULL;
453 const char *pcEnd = NULL;
454
455 uiMemSize = (uint32_t)szLen;
456 pcNewBuf = (char *)malloc(uiMemSize + 1);
457 if (NULL == pcNewBuf)
458 {
459 vdebug("Failed to alloc new buf.\n");
460 return JSON_FAILED;
461 }
462 memcpy(pcNewBuf, szJsonData, szLen);
463 pcNewBuf[uiMemSize] = 0;
464
465 Ret = vtoy_json_parse_value(pcNewBuf, (char *)szJsonData, pstJson, szJsonData, &pcEnd);
466 if (JSON_SUCCESS != Ret)
467 {
468 vdebug("Failed to parse json data start=%p, end=%p\n", szJsonData, pcEnd);
469 return JSON_FAILED;
470 }
471
472 return JSON_SUCCESS;
473 }
474
475 int vtoy_json_scan_parse
476 (
477 const VTOY_JSON *pstJson,
478 uint32_t uiParseNum,
479 VTOY_JSON_PARSE_S *pstJsonParse
480 )
481 {
482 uint32_t i = 0;
483 const VTOY_JSON *pstJsonCur = NULL;
484 VTOY_JSON_PARSE_S *pstCurParse = NULL;
485
486 for (pstJsonCur = pstJson; NULL != pstJsonCur; pstJsonCur = pstJsonCur->pstNext)
487 {
488 if ((JSON_TYPE_OBJECT == pstJsonCur->enDataType) ||
489 (JSON_TYPE_ARRAY == pstJsonCur->enDataType))
490 {
491 continue;
492 }
493
494 for (i = 0, pstCurParse = NULL; i < uiParseNum; i++)
495 {
496 if (0 == strcmp(pstJsonParse[i].pcKey, pstJsonCur->pcName))
497 {
498 pstCurParse = pstJsonParse + i;
499 break;
500 }
501 }
502
503 if (NULL == pstCurParse)
504 {
505 continue;
506 }
507
508 switch (pstJsonCur->enDataType)
509 {
510 case JSON_TYPE_NUMBER:
511 {
512 if (sizeof(uint32_t) == pstCurParse->uiBufSize)
513 {
514 *(uint32_t *)(pstCurParse->pDataBuf) = (uint32_t)pstJsonCur->unData.lValue;
515 }
516 else if (sizeof(uint16_t) == pstCurParse->uiBufSize)
517 {
518 *(uint16_t *)(pstCurParse->pDataBuf) = (uint16_t)pstJsonCur->unData.lValue;
519 }
520 else if (sizeof(uint8_t) == pstCurParse->uiBufSize)
521 {
522 *(uint8_t *)(pstCurParse->pDataBuf) = (uint8_t)pstJsonCur->unData.lValue;
523 }
524 else if ((pstCurParse->uiBufSize > sizeof(uint64_t)))
525 {
526 scnprintf((char *)pstCurParse->pDataBuf, pstCurParse->uiBufSize, "%llu",
527 (unsigned long long)(pstJsonCur->unData.lValue));
528 }
529 else
530 {
531 vdebug("Invalid number data buf size %u.\n", pstCurParse->uiBufSize);
532 }
533 break;
534 }
535 case JSON_TYPE_STRING:
536 {
537 scnprintf((char *)pstCurParse->pDataBuf, pstCurParse->uiBufSize, "%s", pstJsonCur->unData.pcStrVal);
538 break;
539 }
540 case JSON_TYPE_BOOL:
541 {
542 *(uint8_t *)(pstCurParse->pDataBuf) = (pstJsonCur->unData.lValue) > 0 ? 1 : 0;
543 break;
544 }
545 default :
546 {
547 break;
548 }
549 }
550 }
551
552 return JSON_SUCCESS;
553 }
554
555 int vtoy_json_scan_array
556 (
557 VTOY_JSON *pstJson,
558 const char *szKey,
559 VTOY_JSON **ppstArrayItem
560 )
561 {
562 VTOY_JSON *pstJsonItem = NULL;
563
564 pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_ARRAY, szKey);
565 if (NULL == pstJsonItem)
566 {
567 vdebug("Key %s is not found in json data.\n", szKey);
568 return JSON_NOT_FOUND;
569 }
570
571 *ppstArrayItem = pstJsonItem;
572
573 return JSON_SUCCESS;
574 }
575
576 int vtoy_json_scan_array_ex
577 (
578 VTOY_JSON *pstJson,
579 const char *szKey,
580 VTOY_JSON **ppstArrayItem
581 )
582 {
583 VTOY_JSON *pstJsonItem = NULL;
584
585 pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_ARRAY, szKey);
586 if (NULL == pstJsonItem)
587 {
588 vdebug("Key %s is not found in json data.\n", szKey);
589 return JSON_NOT_FOUND;
590 }
591
592 *ppstArrayItem = pstJsonItem->pstChild;
593
594 return JSON_SUCCESS;
595 }
596
597 int vtoy_json_scan_object
598 (
599 VTOY_JSON *pstJson,
600 const char *szKey,
601 VTOY_JSON **ppstObjectItem
602 )
603 {
604 VTOY_JSON *pstJsonItem = NULL;
605
606 pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_OBJECT, szKey);
607 if (NULL == pstJsonItem)
608 {
609 vdebug("Key %s is not found in json data.\n", szKey);
610 return JSON_NOT_FOUND;
611 }
612
613 *ppstObjectItem = pstJsonItem;
614
615 return JSON_SUCCESS;
616 }
617
618 int vtoy_json_get_int
619 (
620 VTOY_JSON *pstJson,
621 const char *szKey,
622 int *piValue
623 )
624 {
625 VTOY_JSON *pstJsonItem = NULL;
626
627 pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_NUMBER, szKey);
628 if (NULL == pstJsonItem)
629 {
630 //vdebug("Key %s is not found in json data.\n", szKey);
631 return JSON_NOT_FOUND;
632 }
633
634 *piValue = (int)pstJsonItem->unData.lValue;
635
636 return JSON_SUCCESS;
637 }
638
639 int vtoy_json_get_uint
640 (
641 VTOY_JSON *pstJson,
642 const char *szKey,
643 uint32_t *puiValue
644 )
645 {
646 VTOY_JSON *pstJsonItem = NULL;
647
648 pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_NUMBER, szKey);
649 if (NULL == pstJsonItem)
650 {
651 vdebug("Key %s is not found in json data.\n", szKey);
652 return JSON_NOT_FOUND;
653 }
654
655 *puiValue = (uint32_t)pstJsonItem->unData.lValue;
656
657 return JSON_SUCCESS;
658 }
659
660 int vtoy_json_get_uint64
661 (
662 VTOY_JSON *pstJson,
663 const char *szKey,
664 uint64_t *pui64Value
665 )
666 {
667 VTOY_JSON *pstJsonItem = NULL;
668
669 pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_NUMBER, szKey);
670 if (NULL == pstJsonItem)
671 {
672 vdebug("Key %s is not found in json data.\n", szKey);
673 return JSON_NOT_FOUND;
674 }
675
676 *pui64Value = (uint64_t)pstJsonItem->unData.lValue;
677
678 return JSON_SUCCESS;
679 }
680
681 int vtoy_json_get_bool
682 (
683 VTOY_JSON *pstJson,
684 const char *szKey,
685 uint8_t *pbValue
686 )
687 {
688 VTOY_JSON *pstJsonItem = NULL;
689
690 pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_BOOL, szKey);
691 if (NULL == pstJsonItem)
692 {
693 vdebug("Key %s is not found in json data.\n", szKey);
694 return JSON_NOT_FOUND;
695 }
696
697 *pbValue = pstJsonItem->unData.lValue > 0 ? 1 : 0;
698
699 return JSON_SUCCESS;
700 }
701
702 int vtoy_json_get_string
703 (
704 VTOY_JSON *pstJson,
705 const char *szKey,
706 uint32_t uiBufLen,
707 char *pcBuf
708 )
709 {
710 VTOY_JSON *pstJsonItem = NULL;
711
712 pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_STRING, szKey);
713 if (NULL == pstJsonItem)
714 {
715 //vdebug("Key %s is not found in json data.\n", szKey);
716 return JSON_NOT_FOUND;
717 }
718
719 scnprintf(pcBuf, uiBufLen, "%s", pstJsonItem->unData.pcStrVal);
720
721 return JSON_SUCCESS;
722 }
723
724 const char * vtoy_json_get_string_ex(VTOY_JSON *pstJson, const char *szKey)
725 {
726 VTOY_JSON *pstJsonItem = NULL;
727
728 if ((NULL == pstJson) || (NULL == szKey))
729 {
730 return NULL;
731 }
732
733 pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_STRING, szKey);
734 if (NULL == pstJsonItem)
735 {
736 //vdebug("Key %s is not found in json data.\n", szKey);
737 return NULL;
738 }
739
740 return pstJsonItem->unData.pcStrVal;
741 }
742
743 int vtoy_json_destroy(VTOY_JSON *pstJson)
744 {
745 if (NULL == pstJson)
746 {
747 return JSON_SUCCESS;
748 }
749
750 if (NULL != pstJson->pstChild)
751 {
752 vtoy_json_free(pstJson->pstChild);
753 }
754
755 if (NULL != pstJson->pstNext)
756 {
757 vtoy_json_free(pstJson->pstNext);
758 }
759
760 free(pstJson);
761
762 return JSON_SUCCESS;
763 }
764
765 int vtoy_json_escape_string(char *buf, int buflen, const char *str, int newline)
766 {
767 char last = 0;
768 int count = 0;
769
770 *buf++ = '"';
771 count++;
772
773 while (*str)
774 {
775 if (*str == '"' && last != '\\')
776 {
777 *buf = '\\';
778 count++;
779 buf++;
780 }
781
782 *buf = *str;
783 count++;
784 buf++;
785
786 last = *str;
787 str++;
788 }
789
790 *buf++ = '"';
791 count++;
792
793 *buf++ = ',';
794 count++;
795
796 if (newline)
797 {
798 *buf++ = '\n';
799 count++;
800 }
801
802 return count;
803 }