* Deconstruct the text representation of a 1-dimensional Postgres array * into individual items. * * On success, returns true and sets *itemarray and *nitems to describe * an array of individual strings. On parse failure, returns false; * *itemarray may exist or be NULL. * * NOTE: free'ing itemarray is sufficient to deallocate the working storage. */
| 837 | * NOTE: free'ing itemarray is sufficient to deallocate the working storage. |
| 838 | */ |
| 839 | bool |
| 840 | parsePGArray(const char *atext, char ***itemarray, int *nitems) |
| 841 | { |
| 842 | int inputlen; |
| 843 | char **items; |
| 844 | char *strings; |
| 845 | int curitem; |
| 846 | |
| 847 | /* |
| 848 | * We expect input in the form of "{item,item,item}" where any item is |
| 849 | * either raw data, or surrounded by double quotes (in which case embedded |
| 850 | * characters including backslashes and quotes are backslashed). |
| 851 | * |
| 852 | * We build the result as an array of pointers followed by the actual |
| 853 | * string data, all in one malloc block for convenience of deallocation. |
| 854 | * The worst-case storage need is not more than one pointer and one |
| 855 | * character for each input character (consider "{,,,,,,,,,,}"). |
| 856 | */ |
| 857 | *itemarray = NULL; |
| 858 | *nitems = 0; |
| 859 | inputlen = strlen(atext); |
| 860 | if (inputlen < 2 || atext[0] != '{' || atext[inputlen - 1] != '}') |
| 861 | return false; /* bad input */ |
| 862 | items = (char **) malloc(inputlen * (sizeof(char *) + sizeof(char))); |
| 863 | if (items == NULL) |
| 864 | return false; /* out of memory */ |
| 865 | *itemarray = items; |
| 866 | strings = (char *) (items + inputlen); |
| 867 | |
| 868 | atext++; /* advance over initial '{' */ |
| 869 | curitem = 0; |
| 870 | while (*atext != '}') |
| 871 | { |
| 872 | if (*atext == '\0') |
| 873 | return false; /* premature end of string */ |
| 874 | items[curitem] = strings; |
| 875 | while (*atext != '}' && *atext != ',') |
| 876 | { |
| 877 | if (*atext == '\0') |
| 878 | return false; /* premature end of string */ |
| 879 | if (*atext != '"') |
| 880 | *strings++ = *atext++; /* copy unquoted data */ |
| 881 | else |
| 882 | { |
| 883 | /* process quoted substring */ |
| 884 | atext++; |
| 885 | while (*atext != '"') |
| 886 | { |
| 887 | if (*atext == '\0') |
| 888 | return false; /* premature end of string */ |
| 889 | if (*atext == '\\') |
| 890 | { |
| 891 | atext++; |
| 892 | if (*atext == '\0') |
| 893 | return false; /* premature end of string */ |
| 894 | } |
| 895 | *strings++ = *atext++; /* copy quoted data */ |
| 896 | } |
no outgoing calls
no test coverage detected