Blog

  • SALUTE THE RAINBOW FLAG

    The most potent weapon against the lesbian and gay community has been the stereotypes that we have ourselves aided in creating. Our parades are videotaped, but only our campiest brethren are not edited out; our statements are recorded, but only the most extreme are heard; our disagreements are noted, but only the most politically correct are not filtered out. We find ourselves portrayed as an army of leather and feather clad politically correct hot-heads marching in lockstep (in heels??) to the beat of the same drummer.

    And yet, when any group raises its head, not to denounce our more eccentrically coffered siblings, but to disagree with the community’s self appointed coat-and-tie leadership, we are ostracized.

    It is not too much to say that there is a concerted effort within the gay and lesbian community to suppress the pro-life message. If you come forth as a pro-life gay man or lesbian, you are likely to be accused of sedition. To speak in defense of the unborn is to violate the last taboo of the gay community. The argument that sexual privacy rights necessarily are dependent on abortion rights is specious. In the 1973 the Supreme Court ruled that abortion was a constitutionally protected privacy right: In 1986 the Supreme Court ruled that consensual homosexual relations were not. Therefore, for lesbians and gays this specific constitutional theory of privacy rights is irrelevant.

    When was the last time that the Human Rights Campaign Fund or any local gay political action committees endorsed a pro-life candidate for office – even if that candidate was also pro gay? And what about a the routine diversion of funds raised by AIDS walks to abortion providers – and this in the name of compassion for people with with AIDS? Pro-life gays and to lesbians – even those who have lost loved ones AIDS – have actually found themselves excluded from AIDS walks because they objected to this practice. When any march or rally is proposed to seek redress of a grievance of the lesbian and gay community – anti-gay violence, for example – it must be joined in equal measure with a demand for reproductive freedom and abortion on demand. We are exhorted in our publications and e-mail to resist any restriction on abortion as if it intended to replace the daily execution of 4400 of the unborn with 4400 of our own.

    Of all Americans, those of us in the sexual minority community have the most reason to be concerned about protecting human life. After all, we know what it is to have our lives and rights trampled on, especially the basic human right just to keep on living. Homophobia has placed our right to life in danger every day: ask anyone who has been bashed or someone whose insurance will not cover lifesaving medical care. We fight back in every way that we can: we organize, we lobby, we vote. We claim the same basic rights heterosexuals take for granted.

    But lesbian and gay Americans are not the only ones whose rights are jeopardized. Everyday, the ugly face of prejudice shows itself when the rights of others are shortchanged because of gender, race, state of health, ethnicity, religion, politics, etc. The gay community has come to the realization that we cannot work for our own rights alone but must work to achieve basic human rights for all those who suffer discrimination.

    Why? Because our rights and the rights of others are the same human rights. As gay men and lesbian women, we stay that all human life deserves dignity and respect. No human life should be considered expendable and the basic right to live should be guaranteed without threat or harassment. That includes the unborn, a voiceless minority with no defense against the worst of all abuses: death. Some 4400 are wiped out every day. Why must we speak for unborn people? Simply because they are people. To be pro-life and pro-gay is to affirm that human rights are not discretionary.

    America’s abortion policy violates this basic concept of human rights. Just like homophobia, abortion denies people their status as members of human society. Just like homophobia, abortion tries to rid society of real human beings who are considered threatening or undesirable. Just like homophobia, abortion denies one’s place as a member of human society and even one’s right to be alive in it.

    No, not all lesbians and gays are “pro-choice” and it is far past the time when the stereotype imposed on us by some of the “leaders” of our community attempt to force upon us is removed. No survey suggests that members of the sexual minority community are any more pro-choice than the average American. While equal rights have not yet been won, we have grown into a community as diverse as the nation. Closet doors have been abandoned by the thousands. Invisibility and fear are fading into history. Gays and lesbians come from many different backgrounds and hold widely differing belief on many issues. We represent a diversity and pluralism of beliefs at which the rainbow flag only hints. To attempt to enforce a “party line” on all members of our community is to betray the very cause we are fighting for: The right to be different.

    For years, mainstream society has rightly been condemned for not letting lesbians and gays participate fully in the American dream. Now we, in turn, are not permitting our own to be fully active in gay society. We wave rainbow flags and envision multi-colored mosaics but somehow these colors fade away when gay pro-lifers attempt to join the parade. Gays and lesbians who tout ideological diversity prove themselves hypocrites when they ostracize gay pro-lifers.

    If the gay movement is to win the struggle against bigotry and intolerance in mainstream American society, it must first eliminate bigotry and intolerance within it own ranks. We must not do the work of homophobes for them by stereotyping ourselves and enforcing a blanket of political correctness. Even worse, they hinder our entire march of civil rights. When gays and lesbians stereotype themselves with a uniform of political correctness, we make it easy for anti-gay fanatics to smear all of us.

    The existence of the Pro-Life Alliance of Gays and Lesbians (PLAGAL) shreds both the stereotype which the lesbian and gay community has of pro-lifers as well as the stereotype which the straight community has of lesbian and gay Americans. The voices of lesbian and gay pro-lifers are testimony that gays and lesbians are, indeed, everywhere.

    Twenty-five years ago others fought for our rights at Stonewall and we can best honor their memory by defending the rights of others today. Not only the rights of unborn Americans, but also the free speech rights of gay and lesbian Americans. After all, the fight at Stonewall was for our right to be different, not merely to replace the conformity demands of straight society with the conformity demands of certain elements of gay and lesbian society. The freedom of gays and lesbians – not the extermination of the unborn – must be the benchmark for gay liberation.

    Abortion proponents have targeted the LGBТ community with a position paper to the effect that our rights are dependent on the judicially created “right to privacy” which is the foundation upon which Roe v. Wade, and hence abortion, is based. The parallel analysis of changes in abortion rights with changes in gay rights shows how specious this argument is.

    Since the Roe v. Wade decision of 1973, there has been a slow and consistent erosion of abortion-on-demand with the imposition of mandatory counseling, waiting periods, and parental notification. Prohibitions against the expenditure of federal funds as well as state funds have been found constitutional. International family agencies receiving U.S. aid have been prevented from counseling for abortion. Casey v. Planned Parenthood replaced Roe v. Wade as the law of the land on abortion; it replaced the “strict scrutiny” test of state anti-abortion laws with a much weaker “undue burden” test, with four of the nine justices calling for an outright reversal of Roe. Thirty-two states now require parental notification and 18 states require waiting periods and counseling as to risks and fetal development. Both houses of Congress have voted to ban “partial birth” abortions. And the number of abortions has been steadily declining for at least a decade.

    As abortion rights have been undergoing a consistent cutback, there has been a simultaneous expansion of gay rights. In 1961, all states and the District of Columbia had anti-sodomy laws. By the time of the infamous Bowers v Hardwick decision in 1976, fully 50% of the states had already decriminalized sodomy. Bowers held anti-sodomy laws constitutional and stated that the fact that homosexual conduct occurs in the privacy of the home does not affect the result. Bowers was decided fully three years after Roe v. Wade, giving giving lie to the argument that the “right to privacy” had any application to the LGBT community: “Respondent would have us announce …a fundamental right to engage in homosexual sodomy. the This we are quite unwilling to do.” This is the same court, which by a 7 to 2 holding, found a fundamental right in the abortion process.

    When Bowers was specifically overruled by Lawrence v. Texas in 2003, the 25 states that had outlawed sodomy in Bowers had been reduced to only 13, of which only 4 enforced their laws against homosexual conduct. In dissent, Justice Scalia noted that the LGBT community had had considerable success in promoting their agenda to decriminalize sodomy through democratic means. To be sure, there is plenty of language in Lawrence as to “privacy,” but it has little, if any, relevancy to the actual holding based on the due process clause of the 14th Amendment.

    Gay marriage (civil unions, domestic partnerships) is currently a hot public policy issue, but it is the very antithesis of a privacy right because it seeks state action for the approval and sanction of LGBT relationships. Because the marriage contract is a three-party contract (the state is the third party) there can be no meaningful talk of a “right to privacy.” The issue of marital equality is one which has just started, with a few states taking positive steps and The several states taking negative ones. The LGBT community need not fear the competition in the marketplace of ideas.

    Other than gay marriage (which does not concern the right to privacy) and sodomy (which has been won largely by the democratic process and not litigation) the Supreme Court’s only other gay decision, Romer v. Evans, is based on equal protection of the laws and not the right to privacy. Romer disallowed a Colorado constitutional amendment which would have denied gays the protection of anti-discrimination laws. The argument for the right to privacy (“get out of my bedroom") is an appealing one for the LGBT community but it has nothing to do with the advancement of gay rights since the movement began with the Stonewall Riots of 1964. The long fight to decriminalize gay sexual behavior was won state by state through the democratic process. The success was so absolute prior to the Lawrence decision that homosexual sodomy was outlawed in only 4 of the 50 states, and even in those states it was not enforced, leading Justice Thomas to call it an “uncommonly silly” law. The fight for marriage equality is a public policy issue outside any privacy concerns. Any other gay court decision has addressed equal protection of the laws, once again not sounding in any “right to privacy.”

    The position paper put forth by abortion advocates is a thinly veiled attempt to shore up rapidly fading support for abortion-on-demand. Gay Americans, much like their counterparts in straight America, have differing philosophical, religious, moral, ethical, and pragmatic attitudes toward abortion. This appeal to our self-interest will fail as will the attempt to divide and conquer. Abortion advocates have attempted to divide men from women, rich from poor, white from black, religious from secular but it appears all this hard work will come to naught. Abortion rights will fail because, unlike gay rights, they are not the result of a democratic process but rather a brand new “constitutional right” created by a court impatient with democratic change.


    Rainbow Pro-Life Alliance Historical Preservation Project

    Source of this Article: https://mads.si.edu/mads/id/NMAH-AC1146-B041-F025

  • AAA-Linux: Chapter 8: User Input

    This post is a preview of the Linux version of Assembly Arithmetic Algorithms. It is planned to be bigger than the DOS book was and so far I am up to chapter 8 and trying to explain everything I can for Linux users who want to write assembly for modern computers at a speed higher than what was possible using a DOS emulator.

    The first seven chapters have been about teaching the basics of Assembly and getting output of strings and numbers to the screen. All those steps were required for learning Assembly. However, at some point, when you have a program that is meant to do something, you need to have a way for other people, especially those who are not programmers, to be able to give input to direct what the program does.

    There are two main ways of doing this in a console program. The first way is have the program ask for the user to type something from the keyboard and then wait until they write something and press enter. The next program will achieve this. Copy this and try it out and then I will explain after the code how it works.

    FASM Keyboard Input

    format ELF executable
    
    main:
    
    mov dword [radix],10
    mov dword [int_width],1
    
    loop_input:
    
    mov eax,string0
    call putstring
    
    call getstring
    
    mov esi,eax     ;mov the string address in eax to esi
    mov edi,string3 ;mov the "exit" string address to edi
    call strcmp     ;call the function to compare the strings and return eax
    cmp eax,0       ;if eax is 0, the strings are the same
    jz the_end      ;go to the_end if the user typed "exit"
    
    mov eax,string1
    call putstring
    
    mov eax,buf
    call putstring
    call putline
    
    mov eax,string2
    call putstring
    
    mov eax,[count]
    call putint
    call putline
    
    jmp loop_input
    
    the_end:
    mov eax,1
    mov ebx,0
    int 80h
    
    string0 db 'Enter a string from the keyboard: ',0
    string1 db 'string: ',0
    string2 db 'length: ',0
    string3 db 'exit',0
    
    buf db 0x100 dup '?'
    count dd 0
    
    getstring:
    
    mov [count],0 ;set count of characters read during this function to zero
    mov edx,1     ;number of bytes to read
    mov ecx,buf   ;address to store the bytes
    
    getstring_chars:
    
    mov ebx,0     ;read from stdin
    mov eax,3     ;invoke SYS_READ (kernel opcode 3)
    int 80h       ;call the kernel
    
    cmp eax,1     ;was 1 character read?
    jnz getstring_end ; if not, then end this loop
    
    mov al,[ecx]  ;mov last character read into al register
    
    ;check if this character is in the proper range to be part of the string
    
    cmp al,0x20      ;compare with 0x20 (space)
    jb getstring_end ;jump if below to getstring_end label
    cmp al,0x7E      ;compare with 0x7E (tilde)
    ja getstring_end ;jump if above to getstring_end label
    
    ;if neither jump happened, keep the character and
    
    inc [count]   ;increment how many characters we have read
    inc ecx       ;increment address where next byte is read from
    jmp getstring_chars ;jump back to start of loop and keep reading
    
    getstring_end:
    
    mov byte[ecx],0 ;terminate this string with a zero
    
    mov eax,buf ;mov the buffer address to eax for returning the string
    
    ret
    
    ;strcmp compares the string at esi to the one at edi
    ;eax returns 0 if the strings are the same and 1 if different
    ;the algorithm is simple but I will explain it for those who are confused
    
    ;eax is initialized to zero
    ;a byte from each string is loaded into the al and bl registers
    ;the bytes are compared. if they are different, then we jump to the end
    ;However, if they are the same, then we check if one of them is zero
    ;for this purpose it doesn't matter whether we compare al or bl with zero
    ;because it is known that they are the same if the jnz did not take place
    ;if it is zero, this also jumps to the end of the function
    ;If neither jump took place, then we jump to the start of the loop
    ;but when the function finally ends bl will be subtracted from al
    ;this ensures that the function returns zero if the final characters are the same
    
    strcmp:
    
    mov eax,0
    
    strcmp_start:
    
    ;read a byte from each string
    mov al,[edi]
    mov bl,[esi]
    cmp al,bl
    jnz strcmp_end
    
    cmp al,0
    jz strcmp_end
    
    inc edi
    inc esi
    
    jmp strcmp_start
    
    strcmp_end:
    sub al,bl
    
    ret
    
    include 'chastelib32.asm'
    

    The getstring function uses a read system call to read from file descriptor 0 which represents standard input or the keyboard. It reads one character each time with a loop and starts at an address labeled “buf” which was declared as a global variable of 256 bytes which were initialized with question marks. I also defined a variable named count which was used to automatically count how many bytes were read.

    buf db 0x100 dup '?'
    count dd 0
    

    But I feel that the part of this function that needs the most explaining is this section:

    cmp al,0x20      ;compare with 0x20 (space)
    jb getstring_end ;jump if below to getstring_end label
    cmp al,0x7E      ;compare with 0x7E (tilde)
    ja getstring_end ;jump if above to getstring_end label
    

    Because this range of characters from space to tilde is what I have identified as the acceptable range of characters. There is no standard way that makes sense for all strings. For example, someone may want to make a getstring function that only accepts capital letters or that only accepts numbers 0 to 9. I can’t say that there is one way that is the best.

    The program listed above will keep running the loop until the user types “exit” as the string. Each time after it gets the string, it compares the what the user entered to the “exit” string. If the strcmp function returns 0, it means the two strings are the same.

    This particular variant of strcmp is based off of the C function of the same name. You may also remember that I wrote a strlen function for the first example in chapter 7 when I had a string that I wanted to write to a new file.

    I believe that using conventional names of C functions is a good idea because C programmers who read my books will already be familiar with that function and what it does in the C programming language.

    In any case, “exit” was the perfect name for a command to “exit” the program. It is also how you log out of a Linux terminal and is the official name for the system call that exits every program in this book!

    Although using the keyboard for input during a running program is a great interactive way of doing things, there is one way that I enjoy even more. The next program is one that I wrote long before I started writing this book and has been referred to as “chastearg” on my blog and the Flat Assembler Forum. It prints the command line arguments when you add them after the name of the program.

    FASM Command Line Arguments

    format ELF executable
    entry main
    
    include 'chastelib32.asm'
    
    main:
    
    pop eax              ;pop the number of arguments from the stack
    mov [argc],eax       ;save the argument count for later
    
    pop eax              ;pop argument 0 (name of the program)
    dec [argc]           ;subtract 1 from argument count
    
    putarg:
    
    cmp [argc],0         ;check for remaining arguments
    jz putarg_end        ;if none, end the loop and stop printing
    pop eax              ;pop the next argument off the stack
    call putstring       ;print the string and a new line
    call putline
    dec [argc]           ;subtract 1 from argument count
    jmp putarg           ;jump to the beginning of the loop
    
    putarg_end:
    
    mov eax, 1           ; invoke SYS_EXIT (kernel opcode 1)
    mov ebx, 0           ; return 0 status on exit - 'No Errors'
    int 0x80
    
    argc dd 0
    

    What is a Command Line Argument?

    People who come from a Windows environment may not even know what a command line argument is because they are used to pointing and clicking with a mouse. You can’t enter an argument this way. For clarification on this topic, here is some terminal text to clarify what arguments are.

    fasm main.asm
    flat assembler  version 1.73.30  (16384 kilobytes memory)
    2 passes, 481 bytes.
    chmod +x main
    ./main this program has command line arguments
    this
    program
    has
    command
    line
    arguments
    

    When we run fasm and give it the name of the Assembly file we want to assemble, the file is an argument or an option we provide to it. In the above example, main.asm is the file I provide to fasm as an argument.

    After the file is assembled, I run the chmod command with the arguments “+x” and “main” which adds the execution permission to the main executable that was just created.

    Finally, running “./main” followed by more words on the same line causes Linux to interpret them as arguments. They are pushed onto the stack.

    When a program begins on Linux, you can access the number of how many arguments were passed to the program by getting the first number you pop off the stack. In the chastearg program, there is a loop that keeps track of how many arguments are left. While there are some remaining, it keeps popping them into the eax register and calling putstring until there are none left.

    Arguments vs Keyboard Input

    The primary difference between input from the keyboard during a program and passing arguments is that the arguments do not stop the execution of a program and wait for anything. If you have an install script which is meant to compile and install a large program, it is better not to pause it for any reason unless an error happens. Arguments are best in this case so that someone can pass information to it that they want the program to know.

    Keyboard input does have a benefit though. For example, suppose that you ask the user to input a number and then they accidentally input a string that is not recognizable as a number. With keyboard input, you can tell them they made a mistake and ask them to try again. With arguments, you cannot edit them during the program because they are only pushed at the start when the program is run from the terminal.

    Only you can decide which of these methods your program needs, but I hope that my explanation and my strcmp function is helpful for you when you try to write a program that needs input to do different things conditionally.

    Later in this book, I will present a calculator written in Assembly language that builds from this chapter’s keyboard input loop. However, we are not ready for that until I teach you how to separate regular strings from numbers. That will be the subject of the next chapter and I can promise you it is simultaneously the hardest task but also the most useful feature you will need for writing any program that has to read numbers.

  • Abortion prevention: don’t forget about the men

    Consider this situation: A man chooses to have sex with a woman who he knows will go for an abortion if she gets pregnant. She does get pregnant. She goes to an abortionist, who performs the abortion. Which of the three people killed the baby? The father, mother, or abortionist?

    It should be obvious that all three people played a part in the abortion. So no matter what your answer, you are partially correct. The father chose to do the one thing that could result in a pregnancy the mother did not want. The mother chose to abort rather than seeking out alternatives. The abortionist was the final step in causing the death of the baby.

    Keeping all of that in mind, if you could go back and talk to one of the people—the father, mother, or abortionist—and convince them to become pro-life, which one would you choose?

    Again, there’s no one right answer, but I would pick the father. Talking to the abortionist could have a major impact if he’s the only abortionist in town and has no one to replace him, but otherwise, the mother will just go elsewhere for the abortion. Of course talking to the mother is good because if her mind changes, the child will live. But will she have the support of the father? He had expected the mother to have an abortion even before they had sex, which implies that he has no interest in taking care of the child.

    Talking to the father makes sense because he has the power to change his ways and stop creating children who will be killed. He also has the ability to support the mother in taking care of the children he is responsible for, making the mother less likely to want to abort. Many women abort due to fear of being a single mother.

    Outreach to women in crisis pregnancy situations is great, but we need to make sure we’re reaching the men too, rather than placing all of the weight on the women. The idea that men are irrelevant to the abortion debate is incredibly misguided.


    This was a post that I submitted to Kelsey Hazzard at Secular Pro-Life back in 2014. At that time, I was still known as Chandler Klebs. You can still read it where Kelsey posted in on the Secular Pro-Life Blog

    http://blog.secularprolife.org/2014/08/abortion-prevention-dont-forget-about.html

  • update for chastext on DOS

    I used my new getarg function I wrote to improve the DOS version of chastext. Nothing about the behavior of the program has changed but the code is a lot smaller and more readable. This chastext program was the original reason I wrote the chastearg program. I needed to get the command line arguments just write.

    But more importantly, people may not see the value of the chastext program and why it is useful to transform text. For that reason, I took this screenshot of a demo batch file that shows just how much I can modify a text file in stages.

    Besides changing a funny tongue twister about seashells into other things (which made a really great example), I also used the Linux version of chastext to make it possible to assemble my DOS programs with either FASM or NASM. The two assemblers are mostly compatible with each other when doing DOS programming due to the lack of headers in ‘.com’ files. Simply replacing “include” with “%include” is enough to transform my FASM source into NASM source because the % is required for the NASM include directive.

    FASM is my main assembler but making sure it assembles my code in NASM will also make a difference for those following my book, Assembly Arithmetic Algorithms for DOS. The book is complete and available on leanpub but there are possible corrections to the code if necessary.

    And for now, I am also trying to work on the Linux version of the book which will be more work because I have a new angle where I want to compare the Assembly to the C code of the same program. Since Linux developers are more familiar with C, it will help those with C language experience to learn the nature of Assembly language and how it is specifically very useful for Linux systems even more than it is for DOS or Windows.

    Also, the source code of the chastext program is available in its own repository.

    https://github.com/chastitywhiterose/chastext

    C and assembly versions are available which means that it can be either compiled or assembled and run on any operating system that I know about. Almost every platform has a C compiler and my custom assembly programs perform even higher on DOS and Linux than the C version did.

    Between chastehex, chastecmp, and now chastext, I have a small set of development tools that I can use for verifying when my programs are producing the output I want. Each tool was made for a specific need I had in mind.

  • chastarg for DOS

    The chastearg program, which is shortened to chastarg to respect DOS 8.3 filename limits, is a tool for separating command line arguments into multiple lines except preserving those that are quoted and therefore counting as one argument. Quoted strings will print on the same line.

    A key aspect of how this works is the new “getarg” function that I wrote. If you take a look at this small program that uses it, it is very simple.

    main.asm

    org 100h     ;DOS programs start at this address
    
    ;this loop will get all the command line arguments and print them on separate lines
    
    call getarg ;this first call will get the command string
    
    arg_loop:
    call getarg
    cmp ax,0 ;did the getarg function return 0?
    jz arg_loop_end ;if ax was zero, there are no args
    call putstring
    call putline
    jmp arg_loop
    arg_loop_end:
    
    ending:
    mov ax,4C00h ; Exit program
    int 21h
    
    include 'getarg.asm'
    include 'chastelib16.asm'
    
    db 0x48 dup 0 ;add extra bytes to make it 512 bytes exactly
    

    But the getarg function itself is a little bit complicated. I tried my best to comment it so that hopefully other DOS programmers can benefit from this useful function.

    getarg.asm

    ;The getarg function was something I badly needed in order to make my assembly code for DOS easier to read.
    ;It will automatically process the command line arguments if they are available.
    ;
    ;The first time it is run, it returns the whole command string or zero if no args are given
    ;DOS does not allow the program name to be part of the arguments
    ;
    ;Each time after that, it will give you the next argument which is a subtring of the original.
    ;When no more arguments are available, it will always return zero
    ;The program calling this is expected to check for this error and then terminate
    ;or print a message depending on the goals of that program
    
    ;A word of warning though, this function has multiple return statements and is long
    ;However, it is fully featured in that it can recognize quoted strings as being the same argument
    ;This brings full compatibility between my DOS and Linux programs which expect consistent behavior
    
    getarg:
    
    mov bx,[arguments_start] ;get the address of start of arguments
    cmp bx,0 ;is this address zero? (meaning this function was not called before)
    jz get_arg_data ;if it was zero, then get the argument data for the first execution of this function
    
    ;if the start was not zero, then clearly arguments exist and addresses have been saved
    cmp bx,[arguments_end]  ;is the address of the start and end the same?
    jnz find_next_string  ;if they are not the same, find the next sub string
    mov ax,0 ;otherwise, return ax as zero and check this in the main program
    
    ret
    
    find_next_string:
    
    mov bx,[arguments_start] ;get address of current arg
    
    skip_spaces:
    
    cmp byte[bx],' ' ;is this byte a space?
    jnz skip_spaces_end ;if it is not a space, we can end this loop
    inc bx ;otherwise, go to next byte
    jmp skip_spaces ;and keep looping till we find non-space
    skip_spaces_end:
    mov ax,bx ;copy this non-space address to ax register
    
    ;we have found a non-space which is the start of a printable string
    ;but we still have to find the next space and terminate it with a zero!
    
    ;however, there is a special case where we want a string to contain spaces. In this case, I have another routine!
    
    ;check for quoted strings
    cmp byte[bx],0x22 ;is this a double quote -> "
    jz scan_quoted_string
    cmp byte[bx],0x27 ;is this a single quote -> '
    jz scan_quoted_string
    
    find_space:
    cmp byte [bx],' ' ;is this a space?
    jz found_space ;if this was a space, end the loop and terminate with zero
    
    ;we must also check to see if we have reached the terminating zero of the arguments string
    cmp byte[bx],0 ;is this byte a zero?
    jz no_more_args ;if yes this string is already terminated
    
    inc bx
    jmp find_space ; this char was not space, go to the next char
    found_space:
    mov byte[bx],0 ;terminate this string
    
    inc bx ;but go to the next byte
    mov [arguments_start],bx ;and set the new start address for the next call
    
    ret ;We can return ax safely knowing the string ends in a zero
    
    scan_quoted_string:
    
    mov cl,byte[bx] ;mov this quote type to cl
    inc bx ;go to next byte
    mov ax,bx ;set ax to this address which is assumed to be the start of a quoted string
    
    find_end_quote:
    cmp byte[bx],cl ;is this the same quote we started with?
    jz found_end_quote ;if it is, end this loop
    
    ;we must also check to see if we have reached the terminating zero of the arguments string
    ;this avoids a crash if I forgot to add the second quotation mark in the arguments
    cmp byte[bx],0 ;is this byte a zero?
    jz no_more_args ;if yes this string is already terminated
    
    inc bx
    jmp find_end_quote
    found_end_quote:
    mov byte[bx],0 ;terminate this string
    
    inc bx ;but go to the next byte
    mov [arguments_start],bx ;and set the new start address for the next call
    
    ret
    
    no_more_args:
    
    mov [arguments_start],bx ;mov the start to where the string ended
    
    ;now that the start and end addresses are the same
    ;this function will always return zero
    ret
    
    ;this will happen first time this function is called to get the argument data
    get_arg_data:
    mov ax,0      ;zero ax (upper half of ax)
    mov al,[80h] ;load length of the command string from this address
    cmp ax,0
    jz getarg_end
    
    mov bx,0x81  ;mov into bx the address of the start of the argument string
    mov [arguments_start],bx ;save the start of the arguments to this variable
    add bx,ax    ;add the length of the command string to this address
    mov byte[bx],0 ;terminate this with a zero to avoid segfaults when printed with putstring
    mov [arguments_end],bx ;save the end of the arguments to this variable
    mov ax,[arguments_start] ;copy the address of the arguments start to ax
    
    getarg_end:
    ret
    
    ;start and end default to address of zero, which means we have not tested the arguments yet
    arguments_start dw 0
    arguments_end dw 0