menu

Top 1 deals for Aba Software Software

40
Followers

Get all the best deals that Aba Software has to offer right here on BitsDuJour. Click quick, these discounts don't last long, and we update daily! We have deals on Aba Search and Replace, .

If you Follow Aba Software, you'll get emails when deals go live!

Visit the Aba Software website.

Aba Search and Replace Screenshot
Aba Search and Replace (PC) Discount
for PC

Aba Search and Replace

Easily Perform Global Search and Replace Operations

30% Off
 

Vendor Pulse

The latest news, straight from our vendors.

  • Jan 18 at 3:32pm
    On coding with LLMs

    It looks like we are near the peak of the AI mania. The usefulness and the limitations of this technology are clear now. What we see now are attempts to overstretch the idea and apply it where it will never work, much like with blockchain and cryptocurrencies several years ago.

    The ubiquitous AI startups will fail and we will see a decline in stock indexes, as well as a re-evaluation of AI strategies in many companies. I'm not excited about new AI agents, nor scared of becoming irrelevant; I'm bored now. Users are sick of tasteless drawings, trying-to-be-helpful AI summaries, and chat windows popping up from every toaster.

    Please don't get me wrong: there are a lot of areas where LLMs are truly useful. I'm glad that I don't have to write tedious unit tests fully by hand anymore. It's great that you can quickly toss together a throw-away script, translate a function from one programming language to another, or generate something as a starting point when coding in a language that you barely know. The problems arise when you perceive this "something" as a finished product.

    An old book (Code Complete by Steve McConnell) says that writing and reviewing code takes around 30% of an average developer's time. The rest is spent in discussions, replying to emails, reading documentation, troubleshooting, learning, or even personal stuff. The data come from a 1964 research and the proportion certainly depends on the person and the company, but any developer can confirm that they are not working with source code 100% of their time. If we assume the 30% estimate is correct and you can speed up coding by 20%, you can only expect a 5% reduction in the project duration (see Amdahl's law).

    So the promises of creating a complete product in a weekend are unrealistic. Programming is hard. I spend hours debugging UI issues or checking the assembler output and this is my own project coded by hand, so I understand it quite well. If I were vibecoding, it would take more time to find the root cause.

    In my career, I never worked on a project where I would need to generate a lot of mediocre code quickly with an LLM. The usual story goes like this: two Californian guys, working after their day jobs, create a product that suddenly becomes popular. The code is a mess; they hit scalability limits, so they hire a Central European like me because a developer from the Bay Area with the same skills would cost them more; at the same, the salary is higher than what I could earn in my region. So we both tolerate the cultural differences, wild accents, and crazy time zones.

    I gradually debug the issues, make their code better organized and faster. For one company, I managed to make it six times faster. This does not mean that the founders were bad developers; they just cut some corners when creating the first version. But at least, the code was written by a human.

    Many new founders today vibecode, so I think that I will be able to do such consulting work until I die or lose interest. We will see a lot of weird class hierarchies, logical mistakes patched with special case handling, and buggy snippets that the LLM ripped off from GitHub or StackOverflow.

    Less young people will be able to solve technical problems because they will rely on AI when studying. And if you got used to asking ChatGPT for solutions to simple problems, you will never learn how to troubleshoot complex or novel issues that AI cannot help you with. Cognitive skills require training and practice just like physical ones.

    Besides that, prompting is a skill on its own. Sometimes it's easier to write code than to explain verbally in every detail how it should work, especially if English is not your first language.

    I would say that vibecoding only adds another layer of abstraction above high-level programming languages. If your project contains a lot of repetitive AI-generated code, it's a sign that you may benefit from designing a library, a framework, or a DSL (a domain-specific language). Metaprogramming techniques can help in some cases, too.

    As Noam Chomsky noted almost three years ago, LLMs are not a replacement for human mind; they are useful, but cannot think in the way that we do. The mental health impact of AI is under active study now. IMHO, chatting with a video card chip is not something natural for a human being and it certainly creates some information overload. Overall, LLMs don't make software engineering much simpler; they even add complexity when used incorrectly.

    I may add some AI features to Aba Search and Replace in future, but it will never become a privacy-invasive AI agent and your files will always stay on your computer. When developing the app, I only use a locally-running LLM for proofreading texts. No vibecoding, no AI slop. As an experiment, this blog post was written without any help from AI.

  • Jan 11 at 2:33pm
    When msvc::musttail attribute silently fails

    Python developers recently reported a 15% speedup when using the new MSVC musttail attribute to create a threaded interpreter. Unfortunately, I found that MSVC does not always generate a tail call when you use this attribute, which can potentially lead to stack overflow when interpreting a complex program.

    Background

    The musttail attribute, also supported by clang, forces the compiler to generate a tail call for a return statement that calls another function. So instead of a CALL instruction to call this function followed by a RET to return from the current function, it emits a JMP instruction to jump to the next function without creating a new stack frame. MSVC recently added support for this technique, which is useful for p-code interpreters.

    P-code interpreters are traditionally coded as a giant switch statement inside a loop:

    for (each instruction in pcode) {
        switch (opcode) {
            case ADD:
                // do the addition
                break;
            case MUL:
                // do the multiplication
                break;
            ...
        }
    }
    

    The switch statement compiles to an indirect jump. All p-code instructions go through this jump, which makes it hard for the processor to predict the next branch.

    If musttail is supported by your compiler, you can create a function for each p-code instruction and link these functions via a dispatch table:

    function DoAdd(INSTR * instr) {
        // Do the addition
        // ...
        // Move to the next p-code instruction
        instr++;
        return dispatch_table[GetOpcode(instr)](instr); // musttail
    }
    
    function DoMul(INSTR * instr) {
        // Do the multiplication
        // ...
        // Move to the next p-code instruction
        instr++;
        return dispatch_table[GetOpcode(instr)](instr); // musttail
    }
    
    dispatch_table = {
        ADD: DoAdd,
        MUL: DoMul,
        ...
    };
    

    This compiles to an indirect jump in the epilogue of each function. When running your interpreter, the branch predictor will save the branch history separately for each p-code instruction, e.g. if your p-code usually runs MUL after ADD, the processor will remember this. That's why threaded code is usually faster.

    The MSVC problem

    The newly added [[msvc::musttail]] attribute is ignored when the function is moderately complex (so that it saves non-volatile registers on stack) and it has multiple returns (some of them without a tail call):

    void __declspec(noinline) increment(int x) {
        printf("%d\n", x + 1);
    }
    
    void incrementIfPositive(int x) {
        DWORD64 a = GetTickCount64();
        DWORD64 b = GetTickCount64();
        DWORD64 c = GetTickCount64();
        if (c == 0) {
            return;
        }
    
    [[msvc::musttail]]
        return increment(x + (int)(b - a + c / 2));
    }
    

    This is a made-up example, but a similar early return happens in a real interpreter when handling an exception. Assembly output:

    ; 18   :     if (a == 0) {
    
      test  rax, rax
      je    SHORT $LN1@incrementIfPositive
    
    ...
    
    ; 25   :     [[msvc::musttail]]
    ; 26   :     return increment(x + (int)(b - a + c / 2));
    
      shr  rax, 1
      lea  ecx, DWORD PTR [rbx+42]
      sub  eax, edi
      add  ecx, eax
      call ?increment@@YAXH@Z
      mov  rbx, QWORD PTR [rsp+48]
    $LN1@incrementIfPositive:
    
    ; 27   : }
    
      add  rsp, 32          ; 00000020H
      pop  rdi
      ret  0
    ?incrementIfPositive@@YAXH@Z ENDP
    

    Despite the [[msvc::musttail]] attribute, the Visual C++ compiler generates a call to the increment function. I think it’s because the function epilogue is quite long (with add rsp, 32 and pop rdi instructions), so the compiler does not want to duplicate it for the if (c == 0) case. Instead, the compiler generates a conditional jump to $LN1@incrementIfPositive when c == 0, but this prevents the musttail optimization.

    Visual C++ also does not produce any compilation error (as it should do according to the documentation), but just ignores the musttail attribute and generates the call instruction instead of jmp / rex_jmp.

    A workaround that I found is to create a useless handle_exception function and call it instead of returning early:

    int g_x;
    
    void __declspec(noinline) handle_exception(int x) {
        // Do something to avoid optimizing out this function
        g_x = x;
    }
    
    void incrementIfPositive(int x) {
        DWORD64 a = GetTickCount64();
        if (a == 0) {
            return handle_exception(x);
        }
        // The rest of the code is the same
        // ...
    

    Assembly output in this case:

    ; 18   :     if (a == 0) {
    
      test  rax, rax
      jne  SHORT $LN2@incrementIfPositive
    
    ; 27   : }
    
      add  rsp, 32
      pop  rdi
    
    ; 19   :         return handle_exception(x);
    
      jmp  ?handle_exception@@YAXH@Z
    
    ...
    
    ; 24   : 
    ; 25   :     [[msvc::musttail]]
    ; 26   :     return increment(x + (int)(b - a + c / 2));
    
      shr  rax, 1
      lea  ecx, DWORD PTR [rbx+42]
      sub  eax, edi
      add  ecx, eax
      mov  rbx, QWORD PTR [rsp+48]
    
    ; 27   : }
    
      add  rsp, 32
      pop  rdi
    
    ; 24   : 
    ; 25   :     [[msvc::musttail]]
    ; 26   :     return increment(x + (int)(b - a + c / 2));
    
      jmp  ?increment@@YAXH@Z
    ?incrementIfPositive@@YAXH@Z ENDP
    

    Here, a tail call is correctly generated. Unfortunately, this workaround does not help if you have more than one early return from the function. Even if you create several useless functions, it still won't work.

    Conclusion

    I encountered this problem when trying to apply the musttail optimization to the regular expression engine in Aba Search and Replace. I don't know if it affects the Python interpreter, but I reported the bug to Microsoft and it's under their consideration now.

  • Dec 21 2025 at 4:38am
    Mnemonics for hidden controls

    As you may know, you can switch between Windows controls using mnemonics. If you see an underlined character in any Windows application, you can press Alt + this character to set focus to this control or to click a button. For example, in this window, you can press:

    • Alt+D to go to the Decoded JSON Web Token field,
    • Alt+C to click the Copy button, or
    • Alt+F to uncheck the Format JSON option.
    Aba Search and Replace window

    The underlines become visible when you press the Alt key.

    However, if a control is hidden in Win32 (using the ShowWindow function), the mnemonic for it still works. You can still press a hidden button if you know its mnemonic. Imagine you hide a button for unauthorized users, but these users can press it using the Alt+character keyboard shortcut, so this behavior can even create a security vulnerability.

    If your application shows some controls and hides others depending on the state, you may have two controls with the same mnemonic. If one of them is hidden, it may be activated instead of the visible control with the same mnemonic. This happened to me when testing the previous version of Aba Search and Replace.

    The fix is easy: you need to disable a control when you hide it and enable it when you show it. Each ShowWindow call should be paired with an EnableWindow call; you could create a small function that will call both and use it everywhere instead of ShowWindow.

    This quirk applies only to the classic Win32 applications. I've tested with Windows Forms, WPF, and WinUI 3, and you cannot press a hidden button using its mnemonic there. Win32 provides an extra flexibility: you can create a mnemonic that does not correspond to any visible control, but this flexibility is usually not needed and can cause confusion.

  • Sep 7 2025 at 6:25am
    Unix and JavaScript timestamps

    Unix time is the number of seconds elapsed since midnight UTC on January 1, 1970. For example, Unix time was 17‍56684800 on September 1, 2025 at midnight UTC. The counter is independent of the time zone, holding the same value at the same moment in different timezones. It is widely used in C and C++ programming languages, databases (MySQL, PostgreSQL, and SQLite), and file systems (ext3, HFS+, and Reiserfs).

    The counter is typically stored in a 32-bit signed integer, so it can represent dates from December 13, 1901 to January 19, 2038. In 2038, the counter will reach 231−1 and overflow, which is known as the year 2038 problem. Fortunately, most modern implementations have already switched to 64-bit integers.

    Java and JavaScript use the number of milliseconds, not seconds, to represent time since 1970, resulting in a counter with more digits (e.g., 17‍56684800000) that fits in a 64-bit integer. Some other implementations (e.g., Apple File System) count the number of nanoseconds instead.

    The Unix developers chose the epoch of January 1, 1970 because they created the first version of Unix in 1970, so they only needed to represent dates after 1970. Other platforms chose a date close to the introduction of the Gregorian calendar, for example, the Windows counter (the FILETIME structure) starts on January 1, 1601 and the UUID version 1 counter starts on October 15, 1582.

    You can use the following functions in different programming languages to get the current Unix timestamp value:

    • in C/C++, use time_t timestamp = time(NULL);
    • in PHP, use echo time();
    • in Python, use:
    • import time, math
      print(math.ceil(time.time()))
          
    • in JavaScript, use Math.ceil(Date.now() / 1000);
    • in Java, use long timestamp = System.currentTimeMillis() / 1000;
    • in Go, use:
    • import "time"
      timestamp := time.Now().Unix();
      
    • in MySQL, use select unix_timestamp();
    • in PostgreSQL, use select ceil(extract(epoch from current_timestamp));
    • in SQLite, use select strftime('%s');
    Decode Unix timestamp

    Aba Search and Replace can convert Unix/JavaScript timestamps to a date in popular formats including ISO 8601 / RFC 3339, RFC 1123 / RFC 7231, and the Windows system format. It can also perform the reverse conversion and generate the current timestamp.

  • May 10 2025 at 6:29am
    Replace only the Nth match

    Here is another practical task. We need to replace only the second or following match in each file.

    For example, we want to insert <a name="..."> tags before the second and any subsequent headers in each HTML file. There are multiple headers in each file:

    Matching <h2> headers

    And we want to insert a name to be able to refer to each header. The final result should look like this (the added tag is bold):

    <a name="international_search_test"><h2>International search test</h2>
    

    We can solve this task with a lookbehind:

    Matching the second, the third, etc. tags
    (?<=<h2>.*?)<h2>
    

    This regular expression matches <h2>, but only if there is another <h2> before it.

    With Aba Search and Replace, there is a more flexible way to do this. You can match all <h2> tags, but change only the second, the third, etc. tags leaving the first tag intact. The pattern is simple:

    <h2>(.*?)</h2>
    

    But in the replacement, we check if the match number is equal to one:

    \( if Aba.matchNoInFile() == 1 {
       \0
    } else {
       '<a name="' \1.replace(' ', '_').toLower() '">' \0
    } )
    

    If yes, we return the whole match \0 without any change. If not, we add <a name="..."> before it. We also use the toLower function to convert the name to lowercase and the replace function to replace spaces with underscores.

    Replacing the second, the third, etc. tags

    You can easily modify this one-liner to replace the first three tags in each file only, or replace every second tag, which is more complicated with a lookbehind.

BitsDuJour is for People who Love Software
Every day we review great Mac & PC apps, and get you discounts up to 100%
Follow Us
© Copyright 2026 BitsDuJour LLC. Code & Design. All Rights Reserved. Privacy Policy