@@ -767,8 +767,9 @@ bool core_updater_list_parse_network_data(
767767 const char * network_buildbot_url ,
768768 const char * data , size_t len )
769769{
770- char * tok , * save = NULL ;
771770 char * data_buf = NULL ;
771+ char * line = NULL ;
772+ char * data_end = NULL ;
772773
773774 /* Sanity check */
774775 if (!core_list || string_is_empty (data ) || (len < 1 ))
@@ -786,30 +787,68 @@ bool core_updater_list_parse_network_data(
786787 memcpy (data_buf , data , len * sizeof (char ));
787788 data_buf [len ] = '\0' ;
788789
789- /* Split network listing request into lines
790- * and loop over each line.
791- * The outer strtok_r replaces '\n' with '\0' in data_buf,
792- * so each tok is an isolated null-terminated string that
793- * can be safely tokenized in-place by the inner strtok_r
794- * without any extra allocations. */
795- for (tok = strtok_r (data_buf , "\n" , & save ); tok ;
796- tok = strtok_r (NULL , "\n" , & save ))
790+ data_end = data_buf + len ;
791+
792+ /* Parse each line from the network data */
793+ for (line = data_buf ; line < data_end ; )
797794 {
798- char * save2 = NULL ;
795+ char * line_end ;
796+ char * p ;
799797 char * elem0 = NULL ; /* date */
800798 char * elem1 = NULL ; /* crc */
801799 char * elem2 = NULL ; /* filename */
802800
803- if (string_is_empty (tok ))
801+ /* Find end of current line and terminate it */
802+ for (line_end = line ; line_end < data_end && * line_end != '\n' ; line_end ++ )
803+ ;
804+ * line_end = '\0' ;
805+
806+ /* Skip empty lines */
807+ if (string_is_empty (line ))
808+ {
809+ line = line_end + 1 ;
804810 continue ;
811+ }
812+
813+ p = line ;
814+
815+ /* --- elem0: date --- */
816+ /* Skip leading spaces */
817+ while (* p == ' ' )
818+ p ++ ;
819+ if (* p != '\0' )
820+ {
821+ elem0 = p ;
822+ /* Advance to next space and terminate */
823+ while (* p != ' ' && * p != '\0' )
824+ p ++ ;
825+ if (* p == ' ' )
826+ * p ++ = '\0' ;
827+ }
805828
806- /* Split line into listings info components
807- * directly in place - no strdup needed since
808- * strtok_r tracks state via save pointers,
809- * not the input string itself */
810- if ((elem0 = strtok_r (tok , " " , & save2 )) != NULL )
811- if ((elem1 = strtok_r (NULL , " " , & save2 )) != NULL )
812- elem2 = strtok_r (NULL , " " , & save2 );
829+ /* --- elem1: crc --- */
830+ while (* p == ' ' )
831+ p ++ ;
832+ if (* p != '\0' )
833+ {
834+ elem1 = p ;
835+ while (* p != ' ' && * p != '\0' )
836+ p ++ ;
837+ if (* p == ' ' )
838+ * p ++ = '\0' ;
839+ }
840+
841+ /* --- elem2: filename --- */
842+ while (* p == ' ' )
843+ p ++ ;
844+ if (* p != '\0' )
845+ {
846+ elem2 = p ;
847+ while (* p != ' ' && * p != '\0' )
848+ p ++ ;
849+ if (* p == ' ' )
850+ * p = '\0' ;
851+ }
813852
814853 /* Parse listings info and add to core updater
815854 * list */
@@ -824,6 +863,9 @@ bool core_updater_list_parse_network_data(
824863 path_libretro_info ,
825864 network_buildbot_url ,
826865 elem0 , elem1 , elem2 );
866+
867+ /* Advance to next line */
868+ line = line_end + 1 ;
827869 }
828870
829871 /* Temporary data buffer is no longer required */
0 commit comments