FMS  2025.03
Flexible Modeling System
fms_string_utils_binding.c
1 /***********************************************************************
2  * GNU Lesser General Public License
3  *
4  * This file is part of the GFDL Flexible Modeling System (FMS).
5  *
6  * FMS is free software: you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or (at
9  * your option) any later version.
10  *
11  * FMS is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18  **********************************************************************/
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <math.h>
24 
25 // struct to store a string and id associated with that string
26 typedef struct{
27  char arr_name[255];
28  int id;
29 }my_type;
30 
31 // Compares two my_type types by the arr_name
32 static int arr_name_sorter(const void* p1, const void* p2)
33 {
34  const my_type *the_type1 = p1;
35  const my_type *the_type2 = p2;
36 
37  return strcmp(the_type1->arr_name, the_type2->arr_name);
38 }
39 
40 // Sorts an array of strings in alphabetical order
41 // Implements a binary search to search for a string in an array of strings
42 // arr -> pointer of character array
43 // n -> length of the array
44 // id - > indices of the character array
45 void fms_sort_this(char **arr, int* n, int* id)
46 {
47  int i; // For do loops
48  my_type *the_type;
49 
50  // Save the array and the id into a struct
51  the_type = (my_type*)calloc(*n, sizeof(my_type));
52  for(i=0; i<*n; i++){
53  the_type[i].id = id[i];
54  strcpy(the_type[i].arr_name, arr[i]);
55  }
56 
57  qsort(the_type, *n, sizeof(my_type), arr_name_sorter);
58 
59  // Copy the sorted array and the sorted ids
60  for(i=0; i<*n; i++){
61  id[i] = the_type[i].id;
62  strcpy(arr[i], the_type[i].arr_name);
63  }
64 }
65 
66 // Implements a binary search to search for a string in an array of strings
67 // arr -> pointer of character array
68 // n -> length of the array
69 // find me -> string to find
70 // np -> the number of times the string was found
71 // returns a string with the indices ;)
72 char* fms_find_my_string_binding(char** arr, int *n, char *find_me, int *np)
73 {
74  int L= 0; // Left bound
75  int R = *n; // Right bound
76  int m; // Middle of the bound
77  int mm; // Index currently looking at
78  int is_found; // Result from strcmp: 0 if string was found <0 if the string is "less" >0 if the string is "greater"
79  int *p; // Array to store the indices
80  int i; // For do loops
81 
82  *np = 0;
83  is_found = -1;
84  while(L != R){
85  // Start looking in the midle of the array
86  m = ceil((L + R) / 2);
87  //printf("L is set to %i from L=%i and R=%i \n", m, L, R);
88 
89  //printf("Checking %i:%s \n", m, (arr[m]));
90  is_found = strcmp(find_me,(arr[m]));
91  if (is_found == 0)
92  {
93  *np = 1;
94  p = malloc(sizeof(int) * *np);
95  p[*np-1] = m + 1; //Because fortran indices start at 1 ;)
96  //printf("Array found at %i %i %i \n", *np, m, p[*np-1]);
97 
98  // The string can be found in multiple indices of the array, so look to the left of the index where the string
99  // was initially found
100  mm = m;
101  while (is_found == 0) {
102  if (mm != 0) { // Only look to the left if m is not the begining of the array
103  mm= mm -1;
104  is_found = strcmp(find_me,(arr[mm]));
105  if (is_found == 0 ) {
106  *np = *np + 1;
107  p = realloc(p, sizeof(int) * *np);
108  p[*np-1] = mm + 1;
109  //printf("Array found at %i %i %i\n", *np, mm, p[*np-1]);
110  }
111  } else {is_found = -999;} //Done looking
112  }
113  // The string can be found in multiple indices of the array, so look to the right of the index where the string was
114  // initially found
115  mm = m;
116  is_found =0;
117  while (is_found == 0) {
118  if (mm != *n-1) { // Only look to the right if m is not the end of the array
119  mm = mm + 1;
120  is_found = strcmp(find_me,(arr[mm]));
121  if (is_found == 0 ) {
122  *np = *np + 1;
123  p = realloc(p, sizeof(int) * *np);
124  p[*np-1] = mm + 1;
125  //printf("Array found at %i %i %i\n", *np, mm, p[*np-1]);
126  }
127  } else {is_found = -999;} //Done looking}
128  }
129  L = R;
130  // If find_me is greater than arr[m] (i.e find_me="potato" is greater than arr[m]="banana")
131  } else if (is_found > 0) {
132  // Set the lower bound to start in m (ignore the first half)
133  L = m + 1;
134  //printf("L is set to %i \n", L);
135  } else
136  // If find_me is less than arr[m] (i.e find_me="potato" is less than arr[m] = "soccer")
137  {
138  // Set the upper bound to start in m (ignore the lower half)
139  R = m;
140  //printf("R is set to %i \n", R);
141  }
142 
143 }
144 
145  // This is the magical part:
146  // Save the array of indices where the string was found into a string
147  // The fortran side is going to allocate the array to the correct size and read the string into the array
148  // The alternative (normal) way is to have a separate function that gets the number of times the string is found
149  // The fortran side will allocate the array to the correct size and send that into another function that
150  // fill in that array. That will require you to search through the array twice ...
151  char string[255];
152  char *string_p;
153 
154  strcpy(string, "");
155 
156  for(i=0; i<*np; i++){
157  if (i == *np-1) {sprintf( &string[ strlen(string) ], "%d ", p[i] );}
158  else {sprintf( &string[ strlen(string) ], "%d ,", p[i] );}
159  }
160 
161  string_p = (char*) malloc((strlen(string)+1)*sizeof(char));
162  strcpy(string_p, string);
163  return string_p;
164 }
165 
166 /*!
167  * @brief Finds the number of unique strings in an array
168  * @param[in] arr Array of strings
169  * @param[in] n Size of the array
170  * @return Number of unique strings in an array
171  */
172 int fms_find_unique(char** arr, int *n)
173 {
174  int i; // For loops
175  int nfind; // Number of unique strings in an array
176  int * ids = calloc(*n, sizeof(int)); // Array of integers initialized to 0
177 
178  fms_sort_this(arr, n, ids);
179 
180  nfind=1;
181  for(i=1; i<*n; i++){
182  if (strcmp(arr[i], arr[i-1]) != 0){ nfind = nfind + 1;}
183  }
184 
185  return nfind;
186 }
187 
188 /*!
189  * @brief Returns a c string pointer
190  * @param[in] cs Input c string pointer
191  * @return c string pointer
192  */
193 char * cstring2cpointer (char * cs)
194 {
195  return cs;
196 }