@@ -429,7 +429,7 @@ fossil_bluecrab_myshell_error_t fossil_myshell_put(fossil_bluecrab_myshell_t *db
429429 }
430430 }
431431 if (!valid_type ) {
432- return FOSSIL_MYSHELL_ERROR_CONFIG_INVALID ;
432+ return FOSSIL_MYSHELL_ERROR_INVALID_TYPE ;
433433 }
434434
435435 uint64_t key_hash = myshell_hash64 (key );
@@ -536,14 +536,16 @@ fossil_bluecrab_myshell_error_t fossil_myshell_get(
536536 } else {
537537 value_len = hash_comment - (eq + 1 );
538538 }
539- if (value_len >= out_size ) value_len = out_size - 1 ;
539+ // Trim trailing whitespace/newline from value_len
540+ while (value_len > 0 && ((eq + 1 )[value_len - 1 ] == '\n' || (eq + 1 )[value_len - 1 ] == ' ' )) {
541+ value_len -- ;
542+ }
543+ if (value_len >= out_size ) {
544+ * eq = '=' ; // Restore
545+ return FOSSIL_MYSHELL_ERROR_BUFFER_TOO_SMALL ;
546+ }
540547 strncpy (out_value , eq + 1 , value_len );
541548 out_value [value_len ] = '\0' ;
542- // Trim trailing whitespace/newline
543- size_t len = strlen (out_value );
544- while (len > 0 && (out_value [len - 1 ] == '\n' || out_value [len - 1 ] == ' ' )) {
545- out_value [-- len ] = '\0' ;
546- }
547549 * eq = '=' ; // Restore
548550 return FOSSIL_MYSHELL_ERROR_SUCCESS ;
549551 }
@@ -554,14 +556,17 @@ fossil_bluecrab_myshell_error_t fossil_myshell_get(
554556 char * comment = strchr (eq + 1 , '#' );
555557 if (comment ) {
556558 value_len = comment - (eq + 1 );
557- if (value_len >= out_size ) value_len = out_size - 1 ;
559+ // Trim trailing whitespace/newline from value_len
560+ while (value_len > 0 && ((eq + 1 )[value_len - 1 ] == '\n' || (eq + 1 )[value_len - 1 ] == ' ' )) {
561+ value_len -- ;
562+ }
563+ if (value_len >= out_size ) {
564+ * eq = '=' ; // Restore
565+ return FOSSIL_MYSHELL_ERROR_BUFFER_TOO_SMALL ;
566+ }
558567 }
559568 strncpy (out_value , eq + 1 , value_len );
560569 out_value [value_len ] = '\0' ;
561- size_t len = strlen (out_value );
562- while (len > 0 && (out_value [len - 1 ] == '\n' || out_value [len - 1 ] == ' ' )) {
563- out_value [-- len ] = '\0' ;
564- }
565570 * eq = '=' ; // Restore
566571 return FOSSIL_MYSHELL_ERROR_SUCCESS ;
567572 }
@@ -1607,3 +1612,151 @@ fossil_bluecrab_myshell_error_t fossil_myshell_check_integrity(fossil_bluecrab_m
16071612
16081613 return FOSSIL_MYSHELL_ERROR_SUCCESS ;
16091614}
1615+
1616+ fossil_bluecrab_myshell_error_t fossil_myshell_diff (
1617+ const fossil_bluecrab_myshell_t * db1 ,
1618+ const fossil_bluecrab_myshell_t * db2 ,
1619+ char * out_diff ,
1620+ size_t out_size
1621+ ) {
1622+ if (!db1 || !db2 || !db1 -> is_open || !db2 -> is_open || !out_diff || out_size == 0 ) {
1623+ return FOSSIL_MYSHELL_ERROR_INVALID_FILE ;
1624+ }
1625+
1626+ // Advanced diff: compare all commits and staged entries, report adds/removes/changes.
1627+ fseek (db1 -> file , 0 , SEEK_SET );
1628+ fseek (db2 -> file , 0 , SEEK_SET );
1629+
1630+ char line1 [1024 ], line2 [1024 ];
1631+ size_t pos = 0 ;
1632+
1633+ // --- Collect commits from both files ---
1634+ typedef struct { char hash [17 ]; char line [1024 ]; } commit_t ;
1635+ commit_t commits1 [128 ], commits2 [128 ];
1636+ size_t n1 = 0 , n2 = 0 ;
1637+
1638+ while (fgets (line1 , sizeof (line1 ), db1 -> file )) {
1639+ if (strncmp (line1 , "#commit " , 8 ) == 0 ) {
1640+ char hash [17 ] = {0 };
1641+ sscanf (line1 , "#commit %16s" , hash );
1642+ strncpy (commits1 [n1 ].hash , hash , sizeof (commits1 [n1 ].hash ));
1643+ commits1 [n1 ].hash [sizeof (commits1 [n1 ].hash ) - 1 ] = '\0' ;
1644+ strncpy (commits1 [n1 ].line , line1 , sizeof (line1 ));
1645+ n1 ++ ;
1646+ }
1647+ }
1648+ while (fgets (line2 , sizeof (line2 ), db2 -> file )) {
1649+ if (strncmp (line2 , "#commit " , 8 ) == 0 ) {
1650+ char hash [17 ] = {0 };
1651+ strncpy (commits2 [n2 ].hash , hash , 16 );
1652+ commits2 [n2 ].hash [16 ] = '\0' ;
1653+ strncpy (commits2 [n2 ].line , line2 , sizeof (line2 ));
1654+ n2 ++ ;
1655+ n2 ++ ;
1656+ }
1657+ }
1658+
1659+ // --- Compare commits ---
1660+ for (size_t i = 0 ; i < n1 ; ++ i ) {
1661+ bool found = false;
1662+ for (size_t j = 0 ; j < n2 ; ++ j ) {
1663+ if (strcmp (commits1 [i ].hash , commits2 [j ].hash ) == 0 ) {
1664+ found = true;
1665+ if (strcmp (commits1 [i ].line , commits2 [j ].line ) != 0 ) {
1666+ int n = snprintf (out_diff + pos , out_size - pos , "~ %s~ %s" , commits1 [i ].line , commits2 [j ].line );
1667+ if (n < 0 || (size_t )n >= out_size - pos ) return FOSSIL_MYSHELL_ERROR_CAPACITY_EXCEEDED ;
1668+ pos += n ;
1669+ }
1670+ break ;
1671+ }
1672+ }
1673+ if (!found ) {
1674+ int n = snprintf (out_diff + pos , out_size - pos , "- %s" , commits1 [i ].line );
1675+ if (n < 0 || (size_t )n >= out_size - pos ) return FOSSIL_MYSHELL_ERROR_CAPACITY_EXCEEDED ;
1676+ pos += n ;
1677+ }
1678+ }
1679+ for (size_t j = 0 ; j < n2 ; ++ j ) {
1680+ bool found = false;
1681+ for (size_t i = 0 ; i < n1 ; ++ i ) {
1682+ if (strcmp (commits2 [j ].hash , commits1 [i ].hash ) == 0 ) {
1683+ found = true;
1684+ break ;
1685+ }
1686+ }
1687+ if (!found ) {
1688+ int n = snprintf (out_diff + pos , out_size - pos , "+ %s" , commits2 [j ].line );
1689+ if (n < 0 || (size_t )n >= out_size - pos ) return FOSSIL_MYSHELL_ERROR_CAPACITY_EXCEEDED ;
1690+ pos += n ;
1691+ }
1692+ }
1693+
1694+ // --- Collect staged entries from both files ---
1695+ typedef struct { char key [256 ]; char line [1024 ]; } stage_t ;
1696+ stage_t stages1 [128 ], stages2 [128 ];
1697+ size_t s1 = 0 , s2 = 0 ;
1698+
1699+ fseek (db1 -> file , 0 , SEEK_SET );
1700+ while (fgets (line1 , sizeof (line1 ), db1 -> file )) {
1701+ if (strncmp (line1 , "#stage " , 7 ) == 0 ) {
1702+ char * eq = strchr (line1 + 7 , '=' );
1703+ if (eq ) {
1704+ size_t klen = eq - (line1 + 7 );
1705+ strncpy (stages1 [s1 ].key , line1 + 7 , klen );
1706+ stages1 [s1 ].key [klen ] = '\0' ;
1707+ strncpy (stages1 [s1 ].line , line1 , sizeof (line1 ));
1708+ s1 ++ ;
1709+ }
1710+ }
1711+ }
1712+ fseek (db2 -> file , 0 , SEEK_SET );
1713+ while (fgets (line2 , sizeof (line2 ), db2 -> file )) {
1714+ if (strncmp (line2 , "#stage " , 7 ) == 0 ) {
1715+ char * eq = strchr (line2 + 7 , '=' );
1716+ if (eq ) {
1717+ size_t klen = eq - (line2 + 7 );
1718+ strncpy (stages2 [s2 ].key , line2 + 7 , klen );
1719+ stages2 [s2 ].key [klen ] = '\0' ;
1720+ strncpy (stages2 [s2 ].line , line2 , sizeof (line2 ));
1721+ s2 ++ ;
1722+ }
1723+ }
1724+ }
1725+
1726+ // --- Compare staged entries ---
1727+ for (size_t i = 0 ; i < s1 ; ++ i ) {
1728+ bool found = false;
1729+ for (size_t j = 0 ; j < s2 ; ++ j ) {
1730+ if (strcmp (stages1 [i ].key , stages2 [j ].key ) == 0 ) {
1731+ found = true;
1732+ if (strcmp (stages1 [i ].line , stages2 [j ].line ) != 0 ) {
1733+ int n = snprintf (out_diff + pos , out_size - pos , "~ %s~ %s" , stages1 [i ].line , stages2 [j ].line );
1734+ if (n < 0 || (size_t )n >= out_size - pos ) return FOSSIL_MYSHELL_ERROR_CAPACITY_EXCEEDED ;
1735+ pos += n ;
1736+ }
1737+ break ;
1738+ }
1739+ }
1740+ if (!found ) {
1741+ int n = snprintf (out_diff + pos , out_size - pos , "- %s" , stages1 [i ].line );
1742+ if (n < 0 || (size_t )n >= out_size - pos ) return FOSSIL_MYSHELL_ERROR_CAPACITY_EXCEEDED ;
1743+ pos += n ;
1744+ }
1745+ }
1746+ for (size_t j = 0 ; j < s2 ; ++ j ) {
1747+ bool found = false;
1748+ for (size_t i = 0 ; i < s1 ; ++ i ) {
1749+ if (strcmp (stages2 [j ].key , stages1 [i ].key ) == 0 ) {
1750+ found = true;
1751+ break ;
1752+ }
1753+ }
1754+ if (!found ) {
1755+ int n = snprintf (out_diff + pos , out_size - pos , "+ %s" , stages2 [j ].line );
1756+ if (n < 0 || (size_t )n >= out_size - pos ) return FOSSIL_MYSHELL_ERROR_CAPACITY_EXCEEDED ;
1757+ pos += n ;
1758+ }
1759+ }
1760+
1761+ return FOSSIL_MYSHELL_ERROR_SUCCESS ;
1762+ }
0 commit comments